final var netconfNode = configNode.augmentation(NetconfNode.class);
final var nodeOptional = configNode.augmentation(NetconfNodeAugmentedOptional.class);
- requireNonNull(netconfNode.getHost());
- requireNonNull(netconfNode.getPort());
-
// Instantiate the handler ...
final var deviceId = NetconfNodeUtils.toRemoteDeviceId(nodeId, netconfNode);
final var deviceSalFacade = createSalFacade(deviceId, netconfNode.requireLockDatastore());
@Override
public NetconfClientConfigurationBuilder createClientConfigurationBuilder(final NodeId nodeId,
final NetconfNode node) {
- final var builder = NetconfClientConfigurationBuilder.create();
+ final var builder = NetconfClientConfigurationBuilder.create();
+
+ requireNonNull(node.getHost());
+ requireNonNull(node.getPort());
final var protocol = node.getProtocol();
if (node.requireTcpOnly()) {
import org.checkerframework.checker.lock.qual.GuardedBy;
import org.checkerframework.checker.lock.qual.Holding;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.netconf.client.NetconfClientDispatcher;
import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
private final @NonNull List<SchemaSourceRegistration<?>> yanglibRegistrations;
private final @NonNull NetconfClientDispatcher clientDispatcher;
- private final @NonNull NetconfClientConfiguration clientConfig;
private final @NonNull NetconfDeviceCommunicator communicator;
private final @NonNull RemoteDeviceHandler delegate;
private final @NonNull EventExecutor eventExecutor;
private final int minSleep;
private final double sleepFactor;
+ private @Nullable NetconfClientConfiguration clientConfig;
@GuardedBy("this")
private long attempts;
@GuardedBy("this")
@GuardedBy("this")
private Future<?> currentTask;
+ @SuppressWarnings("checkstyle:IllegalCatch")
public NetconfNodeHandler(final NetconfClientDispatcher clientDispatcher, final EventExecutor eventExecutor,
final ScheduledExecutorService keepaliveExecutor, final BaseNetconfSchemas baseSchemas,
final SchemaResourceManager schemaManager, final Executor processingExecutor,
if (keepAliveFacade != null) {
keepAliveFacade.setListener(communicator);
}
-
- clientConfig = builderFactory.createClientConfigurationBuilder(nodeId, node)
- .withSessionListener(communicator)
- .build();
+ // FIXME: move this heavy logic out of constructor
+ try {
+ clientConfig = builderFactory.createClientConfigurationBuilder(nodeId, node)
+ .withSessionListener(communicator)
+ .build();
+ } catch (final Exception exception) {
+ LOG.warn("Error initialization configuration for device {}, using null instead.", deviceId, exception);
+ delegate.onDeviceFailed(exception);
+ clientConfig = null;
+ }
}
public synchronized void connect() {
+ if (clientConfig == null) {
+ LOG.warn("Connection attempts are skipped for device {} because of missing configuration", deviceId);
+ return;
+ }
attempts = 1;
lastSleep = minSleep;
lockedConnect();
synchronized long attempts() {
return attempts;
}
-}
\ No newline at end of file
+}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.doReturn;
import org.junit.Before;
assertSame(sslHandlerFactory, config.getSslHandlerFactory());
}
+ @Test
+ public void testPort() {
+ assertThrows("Port must be specified.", NullPointerException.class, () ->
+ createConfig(nodeBuilder.setPort(null).build()));
+ }
+
+ @Test
+ public void testHost() {
+ assertThrows("Host must be specified.", NullPointerException.class, () ->
+ createConfig(nodeBuilder.setHost(null).build()));
+ }
+
private NetconfClientConfiguration createConfig(final NetconfNode netconfNode) {
return factory.createClientConfigurationBuilder(NODE_ID, netconfNode)
.withSessionListener(sessionListener)
assertEquals(2, handler.attempts());
}
+ /**
+ * Tests the initialization of the NetconfNodeHandler's client configuration.
+ *
+ * <p>
+ * Ensures that no connection attempts are made by the handler after calling connect().
+ */
+ @Test
+ public void testClientConfigInitializationFailure() {
+ doNothing().when(delegate).onDeviceFailed(any(Exception.class));
+ // Creates a netconfNode without specifying a Port and Host.
+ final var netconfNode = new NetconfNodeBuilder()
+ .setReconnectOnChangedSchema(true)
+ .setSchemaless(true)
+ .setTcpOnly(true)
+ .setSleepFactor(Decimal64.valueOf("1.5"))
+ .setConcurrentRpcLimit(Uint16.ONE)
+ // One reconnection attempt
+ .setMaxConnectionAttempts(Uint32.TWO)
+ .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
+ .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
+ .setKeepaliveDelay(Uint32.valueOf(1000))
+ .setConnectionTimeoutMillis(Uint32.valueOf(1000))
+ .setCredentials(new LoginPasswordBuilder().setUsername("testuser").setPassword("testpassword").build())
+ .build();
+ handler = new NetconfNodeHandler(clientDispatcher, eventExecutor, keepaliveExecutor, BASE_SCHEMAS,
+ schemaManager, processingExecutor, new DefaultNetconfClientConfigurationBuilderFactory(encryptionService,
+ credentialProvider,
+ sslHandlerFactoryProvider), deviceActionFactory, delegate, DEVICE_ID, NODE_ID,
+ netconfNode, null);
+ handler.connect();
+ // Expect 0 connection attempts since the clientConfig has not been initialized.
+ assertEquals(0, handler.attempts());
+ }
+
@Test
public void downAfterUpCausesReconnect() {
// Let's borrow common bits