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.controller.config.threadpool.ScheduledThreadPool;
28 import org.opendaylight.controller.config.threadpool.ThreadPool;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
31 import org.opendaylight.netconf.api.NetconfMessage;
32 import org.opendaylight.netconf.client.NetconfClientDispatcher;
33 import org.opendaylight.netconf.client.NetconfClientSessionListener;
34 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
35 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
36 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
37 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
38 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
39 import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
40 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
41 import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas;
42 import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice;
43 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceBuilder;
44 import org.opendaylight.netconf.sal.connect.netconf.NetconfStateSchemasResolverImpl;
45 import org.opendaylight.netconf.sal.connect.netconf.SchemalessNetconfDevice;
46 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
47 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
48 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
49 import org.opendaylight.netconf.sal.connect.netconf.listener.UserPreferences;
50 import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
51 import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
52 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
53 import org.opendaylight.netconf.topology.api.NetconfTopology;
54 import org.opendaylight.netconf.topology.api.SchemaRepositoryProvider;
55 import org.opendaylight.protocol.framework.ReconnectStrategy;
56 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
57 import org.opendaylight.protocol.framework.TimedReconnectStrategy;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
65 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
66 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
67 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
68 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
69 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
70 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
71 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
72 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
73 import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
74 import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
75 import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
79 public abstract class AbstractNetconfTopology implements NetconfTopology {
81 private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfTopology.class);
83 protected static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 60000L;
84 protected static final int DEFAULT_KEEPALIVE_DELAY = 0;
85 protected static final boolean DEFAULT_RECONNECT_ON_CHANGED_SCHEMA = false;
86 protected static final int DEFAULT_CONCURRENT_RPC_LIMIT = 0;
87 private static final int DEFAULT_MAX_CONNECTION_ATTEMPTS = 0;
88 private static final int DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS = 2000;
89 private static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 20000L;
90 private static final BigDecimal DEFAULT_SLEEP_FACTOR = new BigDecimal(1.5);
92 // constants related to Schema Cache(s)
94 * Filesystem based caches are stored relative to the cache directory.
96 private static final String CACHE_DIRECTORY = "cache";
99 * The default cache directory relative to <code>CACHE_DIRECTORY</code>.
101 private static final String DEFAULT_CACHE_DIRECTORY = "schema";
104 * The qualified schema cache directory <code>cache/schema</code>.
106 private static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY =
107 CACHE_DIRECTORY + File.separator + DEFAULT_CACHE_DIRECTORY;
110 * The name for the default schema repository.
112 private static final String DEFAULT_SCHEMA_REPOSITORY_NAME = "sal-netconf-connector";
115 * The default schema repository in the case that one is not specified.
117 private static final SharedSchemaRepository DEFAULT_SCHEMA_REPOSITORY =
118 new SharedSchemaRepository(DEFAULT_SCHEMA_REPOSITORY_NAME);
121 * The default <code>FilesystemSchemaSourceCache</code>, which stores cached files in <code>cache/schema</code>.
123 private static final FilesystemSchemaSourceCache<YangTextSchemaSource> DEFAULT_CACHE =
124 new FilesystemSchemaSourceCache<>(DEFAULT_SCHEMA_REPOSITORY, YangTextSchemaSource.class,
125 new File(QUALIFIED_DEFAULT_CACHE_DIRECTORY));
128 * The default factory for creating <code>SchemaContext</code> instances.
130 private static final SchemaContextFactory DEFAULT_SCHEMA_CONTEXT_FACTORY =
131 DEFAULT_SCHEMA_REPOSITORY.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
134 * Keeps track of initialized Schema resources. A Map is maintained in which the key represents the name
135 * of the schema cache directory, and the value is a corresponding <code>SchemaResourcesDTO</code>. The
136 * <code>SchemaResourcesDTO</code> is essentially a container that allows for the extraction of the
137 * <code>SchemaRegistry</code> and <code>SchemaContextFactory</code> which should be used for a particular
138 * Netconf mount. Access to <code>SCHEMA_RESOURCES_DTO_MAP</code> should be surrounded by appropriate
139 * synchronization locks.
141 private static final Map<String, NetconfDevice.SchemaResourcesDTO> SCHEMA_RESOURCES_DTO_MAP = new HashMap<>();
143 // Initializes default constant instances for the case when the default schema repository
144 // directory cache/schema is used.
146 SCHEMA_RESOURCES_DTO_MAP.put(DEFAULT_CACHE_DIRECTORY,
147 new NetconfDevice.SchemaResourcesDTO(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY,
148 DEFAULT_SCHEMA_CONTEXT_FACTORY,
149 new NetconfStateSchemasResolverImpl()));
150 DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(DEFAULT_CACHE);
151 DEFAULT_SCHEMA_REPOSITORY.registerSchemaSourceListener(
152 TextToASTTransformer.create(DEFAULT_SCHEMA_REPOSITORY, DEFAULT_SCHEMA_REPOSITORY));
155 protected final String topologyId;
156 private final NetconfClientDispatcher clientDispatcher;
157 private final EventExecutor eventExecutor;
158 protected final ScheduledThreadPool keepaliveExecutor;
159 protected final ThreadPool processingExecutor;
160 protected final SharedSchemaRepository sharedSchemaRepository;
161 protected final DataBroker dataBroker;
162 protected final DOMMountPointService mountPointService;
164 protected SchemaSourceRegistry schemaRegistry = DEFAULT_SCHEMA_REPOSITORY;
165 protected SchemaRepository schemaRepository = DEFAULT_SCHEMA_REPOSITORY;
166 protected SchemaContextFactory schemaContextFactory = DEFAULT_SCHEMA_CONTEXT_FACTORY;
168 protected final HashMap<NodeId, NetconfConnectorDTO> activeConnectors = new HashMap<>();
170 protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
171 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
172 final ThreadPool processingExecutor,
173 final SchemaRepositoryProvider schemaRepositoryProvider,
174 final DataBroker dataBroker, final DOMMountPointService mountPointService) {
175 this.topologyId = topologyId;
176 this.clientDispatcher = clientDispatcher;
177 this.eventExecutor = eventExecutor;
178 this.keepaliveExecutor = keepaliveExecutor;
179 this.processingExecutor = processingExecutor;
180 this.sharedSchemaRepository = schemaRepositoryProvider.getSharedSchemaRepository();
181 this.dataBroker = dataBroker;
182 this.mountPointService = mountPointService;
185 public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) {
186 this.schemaRegistry = schemaRegistry;
189 public void setSchemaContextFactory(final SchemaContextFactory schemaContextFactory) {
190 this.schemaContextFactory = schemaContextFactory;
194 public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
195 LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, configNode);
196 return setupConnection(nodeId, configNode);
200 public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
201 LOG.debug("Disconnecting RemoteDevice{{}}", nodeId.getValue());
202 if (!activeConnectors.containsKey(nodeId)) {
203 return Futures.immediateFailedFuture(
204 new IllegalStateException("Unable to disconnect device that is not connected"));
207 // retrieve connection, and disconnect it
208 final NetconfConnectorDTO connectorDTO = activeConnectors.remove(nodeId);
209 connectorDTO.getCommunicator().close();
210 connectorDTO.getFacade().close();
211 return Futures.immediateFuture(null);
214 protected ListenableFuture<NetconfDeviceCapabilities> setupConnection(final NodeId nodeId,
215 final Node configNode) {
216 final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
218 Preconditions.checkNotNull(netconfNode.getHost());
219 Preconditions.checkNotNull(netconfNode.getPort());
220 Preconditions.checkNotNull(netconfNode.isTcpOnly());
222 final NetconfConnectorDTO deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode);
223 final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
224 final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener();
225 final NetconfReconnectingClientConfiguration clientConfig =
226 getClientConfig(netconfClientSessionListener, netconfNode);
227 final ListenableFuture<NetconfDeviceCapabilities> future =
228 deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig);
230 activeConnectors.put(nodeId, deviceCommunicatorDTO);
232 Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
234 public void onSuccess(final NetconfDeviceCapabilities result) {
235 LOG.debug("Connector for : " + nodeId.getValue() + " started succesfully");
239 public void onFailure(final Throwable throwable) {
240 LOG.error("Connector for : " + nodeId.getValue() + " failed");
241 // remove this node from active connectors?
248 protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId,
249 final NetconfNode node) {
250 //setup default values since default value is not supported in mdsal
251 final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null
252 ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis();
253 final Long keepaliveDelay = node.getKeepaliveDelay() == null
254 ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();
255 final Boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
256 ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
258 final IpAddress ipAddress = node.getHost().getIpAddress();
259 final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
260 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
261 node.getPort().getValue());
262 final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
264 RemoteDeviceHandler<NetconfSessionPreferences> salFacade =
265 createSalFacade(remoteDeviceId);
267 if (keepaliveDelay > 0) {
268 LOG.warn("Adding keepalive facade, for device {}", nodeId);
269 salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, keepaliveExecutor.getExecutor(),
270 keepaliveDelay, defaultRequestTimeoutMillis);
273 // pre register yang library sources as fallback schemas to schema registry
274 final List<SchemaSourceRegistration<YangTextSchemaSource>> registeredYangLibSources = Lists.newArrayList();
275 if (node.getYangLibrary() != null) {
276 final String yangLibURL = node.getYangLibrary().getYangLibraryUrl().getValue();
277 final String yangLibUsername = node.getYangLibrary().getUsername();
278 final String yangLigPassword = node.getYangLibrary().getPassword();
280 final LibraryModulesSchemas libraryModulesSchemas;
281 if (yangLibURL != null) {
282 if (yangLibUsername != null && yangLigPassword != null) {
283 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
285 libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
288 for (final Map.Entry<SourceIdentifier, URL> sourceIdentifierURLEntry
289 : libraryModulesSchemas.getAvailableModels().entrySet()) {
290 registeredYangLibSources
291 .add(schemaRegistry.registerSchemaSource(
292 new YangLibrarySchemaYangSourceProvider(remoteDeviceId,
293 libraryModulesSchemas.getAvailableModels()),
294 PotentialSchemaSource.create(sourceIdentifierURLEntry.getKey(),
295 YangTextSchemaSource.class, PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
300 final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = setupSchemaCacheDTO(nodeId, node);
301 final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
302 if (node.isSchemaless()) {
303 device = new SchemalessNetconfDevice(remoteDeviceId, salFacade);
305 device = new NetconfDeviceBuilder()
306 .setReconnectOnSchemasChange(reconnectOnChangedSchema)
307 .setSchemaResourcesDTO(schemaResourcesDTO)
308 .setGlobalProcessingExecutor(processingExecutor.getExecutor())
309 .setId(remoteDeviceId)
310 .setSalFacade(salFacade)
314 final Optional<UserPreferences> userCapabilities = getUserCapabilities(node);
315 final int rpcMessageLimit =
316 node.getConcurrentRpcLimit() == null ? DEFAULT_CONCURRENT_RPC_LIMIT : node.getConcurrentRpcLimit();
318 if (rpcMessageLimit < 1) {
319 LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", remoteDeviceId);
322 return new NetconfConnectorDTO(userCapabilities.isPresent()
323 ? new NetconfDeviceCommunicator(remoteDeviceId, device, userCapabilities.get(), rpcMessageLimit)
324 : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit), salFacade);
327 protected NetconfDevice.SchemaResourcesDTO setupSchemaCacheDTO(final NodeId nodeId, final NetconfNode node) {
328 // Setup information related to the SchemaRegistry, SchemaResourceFactory, etc.
329 NetconfDevice.SchemaResourcesDTO schemaResourcesDTO = null;
330 final String moduleSchemaCacheDirectory = node.getSchemaCacheDirectory();
331 // Only checks to ensure the String is not empty or null; further checks related to directory
332 // accessibility and file permissionsare handled during the FilesystemSchemaSourceCache initialization.
333 if (!Strings.isNullOrEmpty(moduleSchemaCacheDirectory)) {
334 // If a custom schema cache directory is specified, create the backing DTO; otherwise,
335 // the SchemaRegistry and SchemaContextFactory remain the default values.
336 if (!moduleSchemaCacheDirectory.equals(DEFAULT_CACHE_DIRECTORY)) {
337 // Multiple modules may be created at once;
338 // synchronize to avoid issues with data consistency among threads.
339 synchronized (SCHEMA_RESOURCES_DTO_MAP) {
340 // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables
341 // if they already exist
342 schemaResourcesDTO = SCHEMA_RESOURCES_DTO_MAP.get(moduleSchemaCacheDirectory);
343 if (schemaResourcesDTO == null) {
344 schemaResourcesDTO = createSchemaResourcesDTO(moduleSchemaCacheDirectory);
345 schemaResourcesDTO.getSchemaRegistry().registerSchemaSourceListener(
346 TextToASTTransformer.create((SchemaRepository) schemaResourcesDTO.getSchemaRegistry(),
347 schemaResourcesDTO.getSchemaRegistry())
349 SCHEMA_RESOURCES_DTO_MAP.put(moduleSchemaCacheDirectory, schemaResourcesDTO);
352 LOG.info("Netconf connector for device {} will use schema cache directory {} instead of {}",
353 nodeId.getValue(), moduleSchemaCacheDirectory, DEFAULT_CACHE_DIRECTORY);
356 LOG.warn("schema-cache-directory for {} is null or empty; using the default {}",
357 nodeId.getValue(), QUALIFIED_DEFAULT_CACHE_DIRECTORY);
360 if (schemaResourcesDTO == null) {
361 schemaResourcesDTO = new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaRepository,
362 schemaContextFactory, new NetconfStateSchemasResolverImpl());
365 return schemaResourcesDTO;
369 * Creates the backing Schema classes for a particular directory.
371 * @param moduleSchemaCacheDirectory The string directory relative to "cache"
372 * @return A DTO containing the Schema classes for the Netconf mount.
374 private NetconfDevice.SchemaResourcesDTO createSchemaResourcesDTO(final String moduleSchemaCacheDirectory) {
375 final SharedSchemaRepository repository = new SharedSchemaRepository(moduleSchemaCacheDirectory);
376 final SchemaContextFactory schemaContextFactory
377 = repository.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
378 setSchemaRegistry(repository);
379 setSchemaContextFactory(schemaContextFactory);
380 final FilesystemSchemaSourceCache<YangTextSchemaSource> deviceCache =
381 createDeviceFilesystemCache(moduleSchemaCacheDirectory);
382 repository.registerSchemaSourceListener(deviceCache);
383 return new NetconfDevice.SchemaResourcesDTO(repository, repository, schemaContextFactory,
384 new NetconfStateSchemasResolverImpl());
388 * Creates a <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory.
390 * @param schemaCacheDirectory The custom cache directory relative to "cache"
391 * @return A <code>FilesystemSchemaSourceCache</code> for the custom schema cache directory
393 private FilesystemSchemaSourceCache<YangTextSchemaSource> createDeviceFilesystemCache(
394 final String schemaCacheDirectory) {
395 final String relativeSchemaCacheDirectory = CACHE_DIRECTORY + File.separator + schemaCacheDirectory;
396 return new FilesystemSchemaSourceCache<>(schemaRegistry, YangTextSchemaSource.class,
397 new File(relativeSchemaCacheDirectory));
400 public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
401 final NetconfNode node) {
403 //setup default values since default value is not supported in mdsal
404 final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null
405 ? DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis();
406 final long maxConnectionAttempts = node.getMaxConnectionAttempts() == null
407 ? DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts();
408 final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null
409 ? DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis();
410 final BigDecimal sleepFactor = node.getSleepFactor() == null ? DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
412 final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue());
414 final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor,
415 maxConnectionAttempts, betweenAttemptsTimeoutMillis, sleepFactor);
416 final ReconnectStrategy strategy = sf.createReconnectStrategy();
418 final AuthenticationHandler authHandler;
419 final Credentials credentials = node.getCredentials();
420 if (credentials instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
421 .netconf.node.credentials.credentials.LoginPassword) {
422 authHandler = new LoginPassword(
423 ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
424 .netconf.node.credentials.credentials.LoginPassword) credentials).getUsername(),
425 ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114
426 .netconf.node.credentials.credentials.LoginPassword) credentials).getPassword());
428 throw new IllegalStateException("Only login/password authentification is supported");
431 return NetconfReconnectingClientConfigurationBuilder.create()
432 .withAddress(socketAddress)
433 .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
434 .withReconnectStrategy(strategy)
435 .withAuthHandler(authHandler)
436 .withProtocol(node.isTcpOnly() ? NetconfClientConfiguration.NetconfClientProtocol.TCP :
437 NetconfClientConfiguration.NetconfClientProtocol.SSH)
438 .withConnectStrategyFactory(sf)
439 .withSessionListener(listener)
443 protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id);
445 private InetSocketAddress getSocketAddress(final Host host, final int port) {
446 if (host.getDomainName() != null) {
447 return new InetSocketAddress(host.getDomainName().getValue(), port);
449 final IpAddress ipAddress = host.getIpAddress();
450 final String ip = ipAddress.getIpv4Address() != null
451 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
452 return new InetSocketAddress(ip, port);
456 private Optional<UserPreferences> getUserCapabilities(final NetconfNode node) {
457 // if none of yang-module-capabilities or non-module-capabilities is specified
458 // just return absent
459 if (node.getYangModuleCapabilities() == null && node.getNonModuleCapabilities() == null) {
460 return Optional.absent();
463 final List<String> capabilities = new ArrayList<>();
465 boolean overrideYangModuleCaps = false;
466 if (node.getYangModuleCapabilities() != null) {
467 capabilities.addAll(node.getYangModuleCapabilities().getCapability());
468 overrideYangModuleCaps = node.getYangModuleCapabilities().isOverride();
471 //non-module capabilities should not exist in yang module capabilities
472 final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities);
473 Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(),
474 "List yang-module-capabilities/capability should contain only module based capabilities. "
475 + "Non-module capabilities used: " + netconfSessionPreferences.getNonModuleCaps());
477 boolean overrideNonModuleCaps = false;
478 if (node.getNonModuleCapabilities() != null) {
479 capabilities.addAll(node.getNonModuleCapabilities().getCapability());
480 overrideNonModuleCaps = node.getNonModuleCapabilities().isOverride();
483 return Optional.of(new UserPreferences(NetconfSessionPreferences
484 .fromStrings(capabilities, CapabilityOrigin.UserDefined), overrideYangModuleCaps, overrideNonModuleCaps));
487 private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
488 private final Long connectionAttempts;
489 private final EventExecutor executor;
490 private final double sleepFactor;
491 private final int minSleep;
493 TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts,
494 final int minSleep, final BigDecimal sleepFactor) {
495 if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
496 connectionAttempts = maxConnectionAttempts;
498 connectionAttempts = null;
501 this.sleepFactor = sleepFactor.doubleValue();
502 this.executor = executor;
503 this.minSleep = minSleep;
507 public ReconnectStrategy createReconnectStrategy() {
508 final Long maxSleep = null;
509 final Long deadline = null;
511 return new TimedReconnectStrategy(executor, minSleep,
512 minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
516 protected static class NetconfConnectorDTO implements AutoCloseable {
518 private final NetconfDeviceCommunicator communicator;
519 private final RemoteDeviceHandler<NetconfSessionPreferences> facade;
521 public NetconfConnectorDTO(final NetconfDeviceCommunicator communicator,
522 final RemoteDeviceHandler<NetconfSessionPreferences> facade) {
523 this.communicator = communicator;
524 this.facade = facade;
527 public NetconfDeviceCommunicator getCommunicator() {
531 public RemoteDeviceHandler<NetconfSessionPreferences> getFacade() {
535 public NetconfClientSessionListener getSessionListener() {
540 public void close() {
541 communicator.close();