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.LoginPasswordHandler;
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.auth.DatastoreBackedPublicKeyAuth;
49 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
50 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
51 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
52 import org.opendaylight.netconf.sal.connect.netconf.listener.UserPreferences;
53 import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
54 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfKeystoreAdapter;
55 import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
56 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
57 import org.opendaylight.netconf.topology.api.NetconfTopology;
58 import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
59 import org.opendaylight.protocol.framework.ReconnectStrategy;
60 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
61 import org.opendaylight.protocol.framework.TimedReconnectStrategy;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.KeyAuth;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPw;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPwUnencrypted;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.key.auth.KeyBased;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.LoginPassword;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.unencrypted.LoginPasswordUnencrypted;
73 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
74 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
75 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
76 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
77 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
78 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
79 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
80 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
81 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
82 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
83 import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
84 import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
85 import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToASTTransformer;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
89 public abstract class AbstractNetconfTopology implements NetconfTopology {
91 private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfTopology.class);
93 protected static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 60000L;
94 protected static final int DEFAULT_KEEPALIVE_DELAY = 0;
95 protected static final boolean DEFAULT_RECONNECT_ON_CHANGED_SCHEMA = false;
96 protected static final int DEFAULT_CONCURRENT_RPC_LIMIT = 0;
97 private static final int DEFAULT_MAX_CONNECTION_ATTEMPTS = 0;
98 private static final int DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS = 2000;
99 private static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 20000L;
100 private static final BigDecimal DEFAULT_SLEEP_FACTOR = new BigDecimal(1.5);
102 // constants related to Schema Cache(s)
104 * Filesystem based caches are stored relative to the cache directory.
106 private static final String CACHE_DIRECTORY = "cache";
109 * The default cache directory relative to <code>CACHE_DIRECTORY</code>.
111 private static final String DEFAULT_CACHE_DIRECTORY = "schema";
114 * The qualified schema cache directory <code>cache/schema</code>.
116 private static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY =
117 CACHE_DIRECTORY + File.separator + DEFAULT_CACHE_DIRECTORY;
120 * The name for the default schema repository.
122 private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
125 * The default schema repository in the case that one is not specified.
127 private static final SharedSchemaRepository DEFAULT_SCHEMA_REPOSITORY =
128 new SharedSchemaRepository(DEFAULT_SCHEMA_REPOSITORY_NAME);
131 * The default <code>FilesystemSchemaSourceCache</code>, which stores cached files in <code>cache/schema</code>.
133 private static final FilesystemSchemaSourceCache<YangTextSchemaSource> DEFAULT_CACHE =
134 new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class,
135 new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY));
138 * The default factory for creating <code>SchemaContext</code> instances.
140 private static final SchemaContextFactory DEFAULT_SCHEMA_CONTEXT_FACTORY =
141 DEFAULT_SCHEMA_REPOSITORY.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
144 * Keeps track of initialized Schema resources. A Map is maintained in which the key represents the name
145 * of the schema cache directory, and the value is a corresponding <code>SchemaResourcesDTO</code>. The
146 * <code>SchemaResourcesDTO</code> is essentially a container that allows for the extraction of the
147 * <code>SchemaRegistry</code> and <code>SchemaContextFactory</code> which should be used for a particular
148 * Netconf mount. Access to <code>SCHEMA_RESOURCES_DTO_MAP</code> should be surrounded by appropriate
149 * synchronization locks.
151 private static final Map<String, NetconfDevice.SchemaResourcesDTO> SCHEMA_RESOURCES_DTO_MAP = new HashMap<>();
153 // Initializes default constant instances for the case when the default schema repository
154 // directory cache/schema is used.
156 SCHEMA_RESOURCES_DTO_MAP.put(DEFAULT_CACHE_DIRECTORY,
157 new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY,
158 DEFAULT_SCHEMA_CONTEXT_FACTORY,
159 new NetconfStateSchemasResolverImpl()));
160 DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_CACHE);
161 DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
162 TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
165 protected final String topologyId;
166 private final NetconfClientDispatcher clientDispatcher;
167 private final EventExecutor eventExecutor;
168 protected final ScheduledThreadPool keepaliveExecutor;
169 protected final ThreadPool processingExecutor;
170 protected final SharedSchemaRepository sharedSchemaRepository;
171 protected final DataBroker dataBroker;
172 protected final DOMMountPointService mountPointService;
173 private final NetconfKeystoreAdapter keystoreAdapter;
174 protected SchemaSourceRegistry schemaRegistry = DEFAULT_SCHEMA_REPOSITORY;
175 protected SchemaRepository schemaRepository = DEFAULT_SCHEMA_REPOSITORY;
176 protected SchemaContextFactory schemaContextFactory = DEFAULT_SCHEMA_CONTEXT_FACTORY;
177 protected String privateKeyPath;
178 protected String privateKeyPassphrase;
179 protected final AAAEncryptionService encryptionService;
180 protected final HashMap<NodeId, NetconfConnectorDTO> activeConnectors = new HashMap<>();
182 protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
183 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
184 final ThreadPool processingExecutor,
185 final SchemaRepositoryProvider schemaRepositoryProvider,
186 final DataBroker dataBroker, final DOMMountPointService mountPointService,
187 final AAAEncryptionService encryptionService) {
188 this.topologyId = topologyId;
189 this.clientDispatcher = clientDispatcher;
190 this.eventExecutor = eventExecutor;
191 this.keepaliveExecutor = keepaliveExecutor;
192 this.processingExecutor = processingExecutor;
193 this.sharedSchemaRepository = schemaRepositoryProvider.getSharedSchemaRepository();
194 this.dataBroker = dataBroker;
195 this.mountPointService = mountPointService;
196 this.encryptionService = encryptionService;
198 this.keystoreAdapter = new NetconfKeystoreAdapter(dataBroker);
201 public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) {
202 this.schemaRegistry = schemaRegistry;
205 public void setSchemaContextFactory(final SchemaContextFactory schemaContextFactory) {
206 this.schemaContextFactory = schemaContextFactory;
210 public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
211 LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, configNode);
212 return setupConnection(nodeId, configNode);
216 public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
217 LOG.debug("Disconnecting RemoteDevice{{}}", nodeId.getValue());
218 if (!activeConnectors.containsKey(nodeId)) {
219 return Futures.immediateFailedFuture(
220 new IllegalStateException("Unable to disconnect device that is not connected"));
223 // retrieve connection, and disconnect it
224 final NetconfConnectorDTO connectorDTO = activeConnectors.remove(nodeId);
225 connectorDTO.getCommunicator().close();
226 connectorDTO.getFacade().close();
227 return Futures.immediateFuture(null);
230 protected ListenableFuture<NetconfDeviceCapabilities> setupConnection(final NodeId nodeId,
231 final Node configNode) {
232 final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
234 Preconditions.checkNotNull(netconfNode.getHost());
235 Preconditions.checkNotNull(netconfNode.getPort());
236 Preconditions.checkNotNull(netconfNode.isTcpOnly());
238 final NetconfConnectorDTO deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode);
239 final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
240 final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener();
241 final NetconfReconnectingClientConfiguration clientConfig =
242 getClientConfig(netconfClientSessionListener, netconfNode);
243 final ListenableFuture<NetconfDeviceCapabilities> future =
244 deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig);
246 activeConnectors.put(nodeId, deviceCommunicatorDTO);
248 Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
250 public void onSuccess(final NetconfDeviceCapabilities result) {
251 LOG.debug("Connector for : " + nodeId.getValue() + " started succesfully");
255 public void onFailure(final Throwable throwable) {
256 LOG.error("Connector for : " + nodeId.getValue() + " failed");
257 // remove this node from active connectors?
259 }, MoreExecutors.directExecutor());
264 protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId,
265 final NetconfNode node) {
266 //setup default values since default value is not supported in mdsal
267 final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null
268 ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis();
269 final Long keepaliveDelay = node.getKeepaliveDelay() == null
270 ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();
271 final Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
272 ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
274 final IpAddress ipAddress = node.getHost().getIpAddress();
275 final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
276 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
277 node.getPort().getValue());
278 final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
280 RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
281 createSalFacade(remoteDeviceId);
283 if (keepaliveDelay > 0) {
284 LOG.warn("Adding keepalive facade, for device {}", nodeId);
285 salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(),
286 keepaliveDelay, defaultRequestTimeoutMillis);
289 // pre register yang library sources as fallback schemas to schema registry
290 final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
291 if (node.getYangLibrary() != null) {
292 final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue();
293 final String yangLibUsername = node.getYangLibrary().getUsername();
294 final String yangLigPassword = node.getYangLibrary().getPassword();
296 final LibraryModulesSchemas libraryModulesSchemas;
297 if (yangLibURL != null) {
298 if (yangLibUsername != null && yangLigPassword != null) {
299 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
301 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
304 for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry
305 : libraryModulesSchemas.getAvailableModels().entrySet()) {
306 registeredYangLibSources
307 .add(schemaRegistry.registerSchemaSource(
308 new YangLibrarySchemaYangSourceProvider(remoteDeviceId,
309 libraryModulesSchemas.getAvailableModels()),
310 PotentialSchemaSource.create(sourceIdentifierURLEntry.getKey(),
311 YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
316 final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
317 final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
318 if (node.isSchemaless()) {
319 device = new SchemalessNetconfDevice(remoteDeviceId, salFacade);
321 device = new NetconfDeviceBuilder()
322 .setReconnectOnSchemasChange(reconnectOnChangedSchema)
323 .setSchemaResourcesDTO(schemaResourcesDTO)
324 .setGlobalProcessingExecutor(processingExecutor.getExecutor())
325 .setId(remoteDeviceId)
326 .setSalFacade(salFacade)
330 final Optional<UserPreferences> userCapabilities = getUserCapabilities(node);
331 final int rpcMessageLimit =
332 node.getConcurrentRpcLimit() == null ? DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit();
334 if (rpcMessageLimit < 1) {
335 LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", remoteDeviceId);
338 return new NetconfConnectorDTO(userCapabilities.isPresent()
339 ? new NetconfDeviceCommunicator(remoteDeviceId, device, userCapabilities.get(), rpcMessageLimit)
340 : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
343 protected NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
344 // Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
345 NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = null;
346 final String moduleSchemaCacheDirectory = node.getSchemaCacheDirectory();
347 // Only checks to ensure the String is not empty or null; further checks related to directory
348 // accessibility and file permissionsare handled during the FilesystemSchemaSourceCache initialization.
349 if (!Strings.isNullOrEmpty(moduleSchemaCacheDirectory)) {
350 // If a custom schema cache directory is specified, create the backing DTO; otherwise,
351 // the SchemaRegistry and SchemaContextFactory remain the default values.
352 if (!moduleSchemaCacheDirectory.equals(DEFAULT_CACHE_DIRECTORY)) {
353 // Multiple modules may be created at once;
354 // synchronize to avoid issues with data consistency among threads.
355 synchronized (SCHEMA_RESOURCES_DTO_MAP) {
356 // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables
357 // if they already exist
358 schemaResourcesDTO = SCHEMA_RESOURCES_DTO_MAP.get(moduleSchemaCacheDirectory);
359 if (schemaResourcesDTO == null) {
360 schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
361 schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
362 TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
363 schemaResourcesDTO.getSchemaRegistry())
365 SCHEMA_RESOURCES_DTO_MAP.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
368 LOG.info("Netconf connector for device {} will use schema cache directory {} instead of {}",
369 nodeId.getValue(), moduleSchemaCacheDirectory, DEFAULT_CACHE_DIRECTORY);
372 LOG.warn("schema-cache-directory for {} is null or empty; using the default {}",
373 nodeId.getValue(), QUALIFIED_DEFAULT_CACHE_DIRECTORY);
376 if (schemaResourcesDTO == null) {
377 schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaRepository,
378 schemaContextFactory, new NetconfStateSchemasResolverImpl());
381 return schemaResourcesDTO;
385 * Creates the backing Schema classes for a particular directory.
387 * @param moduleSchemaCacheDirectory The string directory relative to "cache"
388 * @return A DTO containing the Schema classes for the Netconf mount.
390 private NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
391 final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
392 final SchemaContextFactory contextFactory
393 = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
394 setSchemaRegistry(repository);
395 setSchemaContextFactory(contextFactory);
396 final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
397 createDeviceFilesystemCache(moduleSchemaCacheDirectory);
398 repository.registerSchemaSourceListener(deviceCache);
399 return new NetconfDevice.SchemaResourcesDTO(repository, repository, contextFactory,
400 new NetconfStateSchemasResolverImpl());
404 * Creates a <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory.
406 * @param schemaCacheDirectory The custom cache directory relative to "cache"
407 * @return A <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory
409 private FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
410 final String schemaCacheDirectory) {
411 final String relativeSchemaCacheDirectory = CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
412 return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
413 new File(relativeSchemaCacheDirectory));
417 * Sets the private key path from location specified in configuration file using blueprint.
419 public void setPrivateKeyPath(final String privateKeyPath) {
420 this.privateKeyPath = privateKeyPath;
424 * Sets the private key passphrase from location specified in configuration file using blueprint.
426 public void setPrivateKeyPassphrase(final String privateKeyPassphrase) {
427 this.privateKeyPassphrase = privateKeyPassphrase;
430 public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
431 final NetconfNode node) {
433 //setup default values since default value is not supported in mdsal
434 final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null
435 ? DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis();
436 final long maxConnectionAttempts = node.getMaxConnectionAttempts() == null
437 ? DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts();
438 final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null
439 ? DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis();
440 final BigDecimal sleepFactor = node.getSleepFactor() == null ? DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
442 final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue());
444 final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor,
445 maxConnectionAttempts, betweenAttemptsTimeoutMillis, sleepFactor);
446 final ReconnectStrategy strategy = sf.createReconnectStrategy();
448 final AuthenticationHandler authHandler = getHandlerFromCredentials(node.getCredentials());
450 return NetconfReconnectingClientConfigurationBuilder.create()
451 .withAddress(socketAddress)
452 .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
453 .withReconnectStrategy(strategy)
454 .withAuthHandler(authHandler)
455 .withProtocol(node.isTcpOnly() ? NetconfClientConfiguration.NetconfClientProtocol.TCP :
456 NetconfClientConfiguration.NetconfClientProtocol.SSH)
457 .withConnectStrategyFactory(sf)
458 .withSessionListener(listener)
462 private AuthenticationHandler getHandlerFromCredentials(final Credentials credentials) {
463 if (credentials instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology
464 .rev150114.netconf.node.credentials.credentials.LoginPassword) {
465 final org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology
466 .rev150114.netconf.node.credentials.credentials.LoginPassword loginPassword
467 = (org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology
468 .rev150114.netconf.node.credentials.credentials.LoginPassword) credentials;
469 return new LoginPasswordHandler(loginPassword.getUsername(), loginPassword.getPassword());
471 if (credentials instanceof LoginPwUnencrypted) {
472 final LoginPasswordUnencrypted loginPassword =
473 ((LoginPwUnencrypted) credentials).getLoginPasswordUnencrypted();
474 return new LoginPasswordHandler(loginPassword.getUsername(), loginPassword.getPassword());
476 if (credentials instanceof LoginPw) {
477 final LoginPassword loginPassword = ((LoginPw) credentials).getLoginPassword();
478 return new LoginPasswordHandler(loginPassword.getUsername(),
479 encryptionService.decrypt(loginPassword.getPassword()));
481 if (credentials instanceof KeyAuth) {
482 final KeyBased keyPair = ((KeyAuth) credentials).getKeyBased();
483 return new DatastoreBackedPublicKeyAuth(keyPair.getUsername(), keyPair.getKeyId(),
484 keystoreAdapter, encryptionService);
486 throw new IllegalStateException("Unsupported credential type: " + credentials.getClass());
489 protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id);
491 private InetSocketAddress getSocketAddress(final Host host, final int port) {
492 if (host.getDomainName() != null) {
493 return new InetSocketAddress(host.getDomainName().getValue(), port);
495 final IpAddress ipAddress = host.getIpAddress();
496 final String ip = ipAddress.getIpv4Address() != null
497 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
498 return new InetSocketAddress(ip, port);
502 private Optional<UserPreferences> getUserCapabilities(final NetconfNode node) {
503 // if none of yang-module-capabilities or non-module-capabilities is specified
504 // just return absent
505 if (node.getYangModuleCapabilities() == null && node.getNonModuleCapabilities() == null) {
506 return Optional.absent();
509 final List<String> capabilities = new ArrayList<>();
511 boolean overrideYangModuleCaps = false;
512 if (node.getYangModuleCapabilities() != null) {
513 capabilities.addAll(node.getYangModuleCapabilities().getCapability());
514 overrideYangModuleCaps = node.getYangModuleCapabilities().isOverride();
517 //non-module capabilities should not exist in yang module capabilities
518 final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities);
519 Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(),
520 "List yang-module-capabilities/capability should contain only module based capabilities. "
521 + "Non-module capabilities used: " + netconfSessionPreferences.getNonModuleCaps());
523 boolean overrideNonModuleCaps = false;
524 if (node.getNonModuleCapabilities() != null) {
525 capabilities.addAll(node.getNonModuleCapabilities().getCapability());
526 overrideNonModuleCaps = node.getNonModuleCapabilities().isOverride();
529 return Optional.of(new UserPreferences(NetconfSessionPreferences
530 .fromStrings(capabilities, CapabilityOrigin.UserDefined), overrideYangModuleCaps, overrideNonModuleCaps));
533 private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
534 private final Long connectionAttempts;
535 private final EventExecutor executor;
536 private final double sleepFactor;
537 private final int minSleep;
539 TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts,
540 final int minSleep, final BigDecimal sleepFactor) {
541 if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
542 connectionAttempts = maxConnectionAttempts;
544 connectionAttempts = null;
547 this.sleepFactor = sleepFactor.doubleValue();
548 this.executor = executor;
549 this.minSleep = minSleep;
553 public ReconnectStrategy createReconnectStrategy() {
554 final Long maxSleep = null;
555 final Long deadline = null;
557 return new TimedReconnectStrategy(executor, minSleep,
558 minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
562 protected static class NetconfConnectorDTO implements AutoCloseable {
564 private final NetconfDeviceCommunicator communicator;
565 private final RemoteDeviceHandler<NetconfSessionPreferences> facade;
567 public NetconfConnectorDTO(final NetconfDeviceCommunicator communicator,
568 final RemoteDeviceHandler<NetconfSessionPreferences> facade) {
569 this.communicator = communicator;
570 this.facade = facade;
573 public NetconfDeviceCommunicator getCommunicator() {
577 public RemoteDeviceHandler<NetconfSessionPreferences> getFacade() {
581 public NetconfClientSessionListener getSessionListener() {
586 public void close() {
587 communicator.close();