From fdc5756e29c8f0717fd3c178ca201d07338f98c1 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sat, 27 Jan 2024 16:44:55 +0100 Subject: [PATCH] Introduce NetconfTimer The wiring of a global timer is not quite what we want, as it makes tracking down where and how it is used quite hard. Add an explicit NetconfTimer interface and a default implementation to provide indirection in from on the Netty timer. This has the benefit of reigning in the lifecycle of the timer, so we actually end up sharing it across components properly. JIRA: NETCONF-590 Change-Id: Ib58c9f5668ec859d68432116fe63f954f6eae08e Signed-off-by: Robert Varga --- .../callhome/mount/CallHomeMountService.java | 6 +- .../callhome/mount/CallHomeTopology.java | 4 +- .../IetfZeroTouchCallHomeServerProvider.java | 6 + .../mount/tls/NetconfCallHomeTlsService.java | 6 + .../netconf/northbound/OSGiNetconfServer.java | 5 +- .../topology/impl/NetconfTopologyImpl.java | 18 +-- .../impl/NetconfTopologyImplTest.java | 8 +- .../impl/NetconfTopologyManager.java | 10 +- .../impl/utils/NetconfTopologySetup.java | 12 +- .../impl/MountPointEndToEndTest.java | 4 +- .../impl/NetconfTopologyManagerTest.java | 4 +- .../topology/spi/AbstractNetconfTopology.java | 6 +- .../topology/spi/NetconfNodeHandler.java | 6 +- .../topology/spi/NetconfNodeHandlerTest.java | 4 +- artifacts/pom.xml | 5 + features/odl-netconf-client/pom.xml | 6 - .../src/main/feature/feature.xml | 13 -- .../CallHomeTransportChannelListener.java | 21 ++-- .../server/ssh/CallHomeSshServer.java | 24 ++-- .../server/tls/CallHomeTlsServer.java | 29 ++--- .../server/ssh/CallHomeSshServerTest.java | 46 +++---- .../server/tls/CallHomeTlsServerTest.java | 14 ++- netconf/netconf-netty-util/pom.xml | 4 + .../nettyutil/NetconfSessionNegotiator.java | 8 +- .../AbstractNetconfSessionNegotiatorTest.java | 4 +- .../netconf/nettyutil/Netconf539Test.java | 5 +- .../nettyutil/TestSessionNegotiator.java | 4 +- .../test/tool/NetconfDeviceSimulator.java | 8 +- .../test/tool/TesttoolNegotiationFactory.java | 15 +-- .../test/tool/client/stress/StressClient.java | 40 +++--- .../netconf/test/tool/TestToolTest.java | 6 +- .../client/mdsal/spi/KeepaliveSalFacade.java | 10 +- ...KeepaliveSalFacadeResponseWaitingTest.java | 9 +- .../mdsal/spi/KeepaliveSalFacadeTest.java | 9 +- protocol/netconf-client/pom.xml | 6 + .../client/NetconfClientFactoryImpl.java | 23 ++-- .../NetconfClientSessionNegotiator.java | 11 +- ...NetconfClientSessionNegotiatorFactory.java | 16 +-- .../client/NetconfClientFactoryImplTest.java | 21 ++-- ...onfClientSessionNegotiatorFactoryTest.java | 5 +- .../NetconfClientSessionNegotiatorTest.java | 5 +- protocol/netconf-common/pom.xml | 57 +++++++++ .../src/main/java/module-info.java | 22 ++++ .../netconf/common/NetconfTimer.java | 36 ++++++ .../common/impl/DefaultNetconfTimer.java | 117 ++++++++++++++++++ .../netconf/common/package-info.java | 11 ++ .../NetconfServerSessionNegotiator.java | 4 +- ...NetconfServerSessionNegotiatorFactory.java | 18 +-- .../netconf/server/ConcurrentClientsTest.java | 17 +-- protocol/pom.xml | 1 + 50 files changed, 499 insertions(+), 250 deletions(-) delete mode 100644 features/odl-netconf-client/src/main/feature/feature.xml create mode 100644 protocol/netconf-common/pom.xml create mode 100644 protocol/netconf-common/src/main/java/module-info.java create mode 100644 protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/NetconfTimer.java create mode 100644 protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/impl/DefaultNetconfTimer.java create mode 100644 protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/package-info.java diff --git a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountService.java b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountService.java index e1dddc02c9..cf2af21242 100644 --- a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountService.java +++ b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountService.java @@ -11,7 +11,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import io.netty.channel.Channel; -import io.netty.util.Timer; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Map; @@ -35,6 +34,7 @@ import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder; import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas; import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.shaded.sshd.client.session.ClientSession; import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory; import org.opendaylight.netconf.topology.spi.NetconfNodeHandler; @@ -119,7 +119,7 @@ public final class CallHomeMountService implements AutoCloseable { @Activate @Inject public CallHomeMountService( - final @Reference(target = "(type=global-timer)") Timer timer, + final @Reference NetconfTimer timer, final @Reference NetconfTopologySchemaAssembler schemaAssembler, final @Reference SchemaResourceManager schemaRepositoryProvider, final @Reference BaseNetconfSchemas baseSchemas, @@ -130,7 +130,7 @@ public final class CallHomeMountService implements AutoCloseable { dataBroker, mountService, deviceActionFactory); } - public CallHomeMountService(final String topologyId, final Timer timer, + public CallHomeMountService(final String topologyId, final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider, final BaseNetconfSchemas baseSchemas, final DataBroker dataBroker, final DOMMountPointService mountService, final DeviceActionFactory deviceActionFactory) { diff --git a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java index d3dceb1bf3..2606467a6e 100644 --- a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java +++ b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java @@ -7,13 +7,13 @@ */ package org.opendaylight.netconf.callhome.mount; -import io.netty.util.Timer; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.netconf.client.NetconfClientFactory; import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas; import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology; import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory; import org.opendaylight.netconf.topology.spi.NetconfTopologySchemaAssembler; @@ -22,7 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. // Non-final for mocking class CallHomeTopology extends AbstractNetconfTopology { - CallHomeTopology(final String topologyId, final NetconfClientFactory clientFactory, final Timer timer, + CallHomeTopology(final String topologyId, final NetconfClientFactory clientFactory, final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker, final DOMMountPointService mountPointService, final NetconfClientConfigurationBuilderFactory builderFactory, final BaseNetconfSchemas baseSchemas, diff --git a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/IetfZeroTouchCallHomeServerProvider.java b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/IetfZeroTouchCallHomeServerProvider.java index 83ff5eb05c..89d05b64a4 100644 --- a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/IetfZeroTouchCallHomeServerProvider.java +++ b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/IetfZeroTouchCallHomeServerProvider.java @@ -9,11 +9,14 @@ package org.opendaylight.netconf.callhome.mount; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder; import org.opendaylight.netconf.callhome.server.ssh.CallHomeSshAuthProvider; import org.opendaylight.netconf.callhome.server.ssh.CallHomeSshServer; +import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory; +import org.opendaylight.netconf.common.NetconfTimer; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; @@ -44,6 +47,7 @@ public final class IetfZeroTouchCallHomeServerProvider implements AutoCloseable @Activate @Inject public IetfZeroTouchCallHomeServerProvider( + final @Reference NetconfTimer timer, final @Reference CallHomeMountService mountService, final @Reference CallHomeSshAuthProvider authProvider, final @Reference CallHomeStatusRecorder statusRecorder, @@ -58,6 +62,8 @@ public final class IetfZeroTouchCallHomeServerProvider implements AutoCloseable .withAuthProvider(authProvider) .withStatusRecorder(statusRecorder) .withSessionContextManager(mountService.createSshSessionContextManager()) + .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), 10000L, + NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES)) .build(); } catch (UnknownHostException e) { throw new IllegalArgumentException("Invalid address", e); diff --git a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/tls/NetconfCallHomeTlsService.java b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/tls/NetconfCallHomeTlsService.java index 7377e54117..9a8a3a076e 100644 --- a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/tls/NetconfCallHomeTlsService.java +++ b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/tls/NetconfCallHomeTlsService.java @@ -9,12 +9,15 @@ package org.opendaylight.netconf.callhome.mount.tls; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Optional; import javax.inject.Inject; import javax.inject.Singleton; import org.opendaylight.netconf.callhome.mount.CallHomeMountService; import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder; import org.opendaylight.netconf.callhome.server.tls.CallHomeTlsAuthProvider; import org.opendaylight.netconf.callhome.server.tls.CallHomeTlsServer; +import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory; +import org.opendaylight.netconf.common.NetconfTimer; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; @@ -52,6 +55,7 @@ public class NetconfCallHomeTlsService implements AutoCloseable { @Activate @Inject public NetconfCallHomeTlsService( + final @Reference NetconfTimer timer, final @Reference CallHomeMountService mountService, final @Reference CallHomeTlsAuthProvider authProvider, final @Reference CallHomeStatusRecorder statusRecorder, @@ -68,6 +72,8 @@ public class NetconfCallHomeTlsService implements AutoCloseable { .withStatusRecorder(statusRecorder) .withSessionContextManager( mountService.createTlsSessionContextManager(authProvider, statusRecorder)) + .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), + configuration.timeoutMillis(), NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES)) .build(); } catch (UnknownHostException e) { throw new IllegalArgumentException("invalid host", e); diff --git a/apps/netconf-nb/src/main/java/org/opendaylight/netconf/northbound/OSGiNetconfServer.java b/apps/netconf-nb/src/main/java/org/opendaylight/netconf/northbound/OSGiNetconfServer.java index ee6271593e..c4e3919320 100644 --- a/apps/netconf-nb/src/main/java/org/opendaylight/netconf/northbound/OSGiNetconfServer.java +++ b/apps/netconf-nb/src/main/java/org/opendaylight/netconf/northbound/OSGiNetconfServer.java @@ -10,8 +10,8 @@ package org.opendaylight.netconf.northbound; import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; -import io.netty.util.Timer; import java.util.Map; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory; import org.opendaylight.netconf.server.ServerTransportInitializer; import org.opendaylight.netconf.server.api.SessionIdProvider; @@ -49,8 +49,7 @@ public final class OSGiNetconfServer { final ComponentFactory monitoringFactory, @Reference(target = "(type=mapper-aggregator-registry)") final NetconfOperationServiceFactory mapperAggregatorRegistry, - @Reference(target = "(type=global-timer)") final Timer timer, - @Reference final SessionIdProvider sessionIdProvider, + @Reference final NetconfTimer timer, @Reference final SessionIdProvider sessionIdProvider, final Configuration configuration) { mappers.onAddNetconfOperationServiceFactory(mapperAggregatorRegistry); monitoring = monitoringFactory.newInstance(FrameworkUtil.asDictionary(DefaultNetconfMonitoringService.props( diff --git a/apps/netconf-topology-impl/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java b/apps/netconf-topology-impl/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java index f71cf9356f..11dc3417ac 100644 --- a/apps/netconf-topology-impl/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java +++ b/apps/netconf-topology-impl/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java @@ -8,7 +8,6 @@ package org.opendaylight.netconf.topology.impl; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.netty.util.Timer; import java.util.Collection; import javax.annotation.PreDestroy; import javax.inject.Inject; @@ -25,6 +24,7 @@ import org.opendaylight.netconf.client.NetconfClientFactory; import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas; import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology; import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory; import org.opendaylight.netconf.topology.spi.NetconfNodeUtils; @@ -58,7 +58,7 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology @Activate public NetconfTopologyImpl( @Reference(target = "(type=netconf-client-factory)") final NetconfClientFactory clientFactory, - @Reference(target = "(type=global-timer)") final Timer timer, + @Reference final NetconfTimer timer, @Reference final NetconfTopologySchemaAssembler schemaAssembler, @Reference final SchemaResourceManager schemaRepositoryProvider, @Reference final DataBroker dataBroker, @Reference final DOMMountPointService mountPointService, @@ -72,7 +72,7 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology } public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientclientFactory, - final Timer timer, final NetconfTopologySchemaAssembler schemaAssembler, + final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker, final DOMMountPointService mountPointService, final AAAEncryptionService encryptionService, final NetconfClientConfigurationBuilderFactory builderFactory, final RpcProviderService rpcProviderService, @@ -83,12 +83,12 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR", justification = "DTCL registration of 'this'") - public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory, final Timer timer, - final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider, - final DataBroker dataBroker, final DOMMountPointService mountPointService, - final AAAEncryptionService encryptionService, final NetconfClientConfigurationBuilderFactory builderFactory, - final RpcProviderService rpcProviderService, final BaseNetconfSchemas baseSchemas, - final DeviceActionFactory deviceActionFactory) { + public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory, + final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler, + final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker, + final DOMMountPointService mountPointService, final AAAEncryptionService encryptionService, + final NetconfClientConfigurationBuilderFactory builderFactory, final RpcProviderService rpcProviderService, + final BaseNetconfSchemas baseSchemas, final DeviceActionFactory deviceActionFactory) { super(topologyId, clientFactory, timer, schemaAssembler, schemaRepositoryProvider, dataBroker, mountPointService, builderFactory, deviceActionFactory, baseSchemas); diff --git a/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java b/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java index 2458c85932..117efbc217 100644 --- a/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java +++ b/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java @@ -12,7 +12,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import io.netty.util.Timer; import java.util.List; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; @@ -33,6 +32,7 @@ import org.opendaylight.netconf.client.NetconfClientFactory; import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; import org.opendaylight.netconf.client.mdsal.impl.DefaultBaseNetconfSchemas; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory; import org.opendaylight.netconf.topology.spi.NetconfTopologySchemaAssembler; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host; @@ -66,7 +66,7 @@ class NetconfTopologyImplTest { @Mock private NetconfClientFactory mockedClientFactory; @Mock - private Timer mockedTimer; + private NetconfTimer mockedTimer; @Mock private SchemaResourceManager mockedResourceManager; @Mock @@ -147,8 +147,8 @@ class NetconfTopologyImplTest { } private static class TestingNetconfTopologyImpl extends NetconfTopologyImpl { - TestingNetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory, final Timer timer, - final NetconfTopologySchemaAssembler schemaAssembler, + TestingNetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory, + final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker, final DOMMountPointService mountPointService, final AAAEncryptionService encryptionService, final NetconfClientConfigurationBuilderFactory builderFactory, diff --git a/apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java b/apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java index 77cf2d9081..145994deeb 100644 --- a/apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java +++ b/apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java @@ -15,7 +15,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.MoreExecutors; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.netty.util.Timer; import java.time.Duration; import java.util.Collection; import java.util.Map; @@ -43,6 +42,7 @@ import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas; import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils; import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory; @@ -95,7 +95,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener instanceIdentifier; private final Node node; - private final Timer timer; + private final NetconfTimer timer; private final NetconfTopologySchemaAssembler schemaAssembler; private final ActorSystem actorSystem; private final NetconfClientFactory netconfClientFactory; @@ -71,7 +71,7 @@ public final class NetconfTopologySetup { return schemaAssembler; } - public Timer getTimer() { + public NetconfTimer getTimer() { return timer; } @@ -108,7 +108,7 @@ public final class NetconfTopologySetup { private DataBroker dataBroker; private InstanceIdentifier instanceIdentifier; private Node node; - private Timer timer; + private NetconfTimer timer; private NetconfTopologySchemaAssembler schemaAssembler; private ActorSystem actorSystem; private String topologyId; @@ -171,11 +171,11 @@ public final class NetconfTopologySetup { return new NetconfTopologySetup(this); } - Timer getTimer() { + NetconfTimer getTimer() { return timer; } - public Builder setTimer(final Timer timer) { + public Builder setTimer(final NetconfTimer timer) { this.timer = requireNonNull(timer); return this; } diff --git a/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java b/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java index ce76dc9c12..8c280a68e2 100644 --- a/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java +++ b/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java @@ -32,7 +32,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import com.typesafe.config.ConfigFactory; -import io.netty.util.Timer; import java.io.File; import java.util.Iterator; import java.util.List; @@ -100,6 +99,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider; import org.opendaylight.netconf.client.mdsal.impl.DefaultSchemaResourceManager; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringRpcException; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils; @@ -190,7 +190,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest { @Mock private AAAEncryptionService mockEncryptionService; @Mock - private Timer mockTimer; + private NetconfTimer mockTimer; @Mock private DeviceActionFactory deviceActionFactory; @Mock diff --git a/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java b/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java index 9bd03ae2a9..64a36ce299 100644 --- a/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java +++ b/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java @@ -25,7 +25,6 @@ import static org.opendaylight.mdsal.binding.api.DataObjectModification.Modifica import akka.actor.ActorSystem; import akka.util.Timeout; -import io.netty.util.Timer; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,6 +57,7 @@ import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier; import org.opendaylight.netconf.client.NetconfClientFactory; import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory; import org.opendaylight.netconf.client.mdsal.impl.DefaultSchemaResourceManager; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup; import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils; import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory; @@ -94,7 +94,7 @@ public class NetconfTopologyManagerTest extends AbstractBaseSchemasTest { @Mock private Registration mockRpcReg; @Mock - private Timer timer; + private NetconfTimer timer; @Mock private ExecutorService processingService; @Mock diff --git a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java index 93f818cd78..df5605d018 100644 --- a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java +++ b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java @@ -10,7 +10,6 @@ package org.opendaylight.netconf.topology.spi; import static java.util.Objects.requireNonNull; import com.google.common.annotations.VisibleForTesting; -import io.netty.util.Timer; import java.util.HashMap; import java.util.NoSuchElementException; import java.util.concurrent.ExecutionException; @@ -23,6 +22,7 @@ import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceHandler; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev221225.NetconfNodeAugmentedOptional; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev231121.NetconfNode; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; @@ -45,7 +45,7 @@ public abstract class AbstractNetconfTopology { private final SchemaResourceManager schemaManager; private final BaseNetconfSchemas baseSchemas; private final NetconfClientConfigurationBuilderFactory builderFactory; - private final Timer timer; + private final NetconfTimer timer; protected final NetconfTopologySchemaAssembler schemaAssembler; protected final DataBroker dataBroker; @@ -53,7 +53,7 @@ public abstract class AbstractNetconfTopology { protected final String topologyId; protected AbstractNetconfTopology(final String topologyId, final NetconfClientFactory clientFactory, - final Timer timer, final NetconfTopologySchemaAssembler schemaAssembler, + final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaManager, final DataBroker dataBroker, final DOMMountPointService mountPointService, final NetconfClientConfigurationBuilderFactory builderFactory, final DeviceActionFactory deviceActionFactory, final BaseNetconfSchemas baseSchemas) { diff --git a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java index a025c83cfb..9084c4a158 100644 --- a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java +++ b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java @@ -15,7 +15,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import io.netty.util.Timeout; -import io.netty.util.Timer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CancellationException; @@ -43,6 +42,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; import org.opendaylight.netconf.client.mdsal.spi.KeepaliveSalFacade; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev221225.NetconfNodeAugmentedOptional; @@ -111,7 +111,7 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re private final @NonNull NetconfClientConfiguration clientConfig; private final @NonNull NetconfDeviceCommunicator communicator; private final @NonNull RemoteDeviceHandler delegate; - private final @NonNull Timer timer; + private final @NonNull NetconfTimer timer; private final @NonNull RemoteDeviceId deviceId; private final long maxBackoff; @@ -127,7 +127,7 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re @GuardedBy("this") private Task currentTask; - public NetconfNodeHandler(final NetconfClientFactory clientFactory, final Timer timer, + public NetconfNodeHandler(final NetconfClientFactory clientFactory, final NetconfTimer timer, final BaseNetconfSchemas baseSchemas, final SchemaResourceManager schemaManager, final NetconfTopologySchemaAssembler schemaAssembler, final NetconfClientConfigurationBuilderFactory builderFactory, diff --git a/apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandlerTest.java b/apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandlerTest.java index 165fb5ccf5..8c05becd2d 100644 --- a/apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandlerTest.java +++ b/apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandlerTest.java @@ -24,7 +24,6 @@ import com.google.common.net.InetAddresses; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.SettableFuture; import io.netty.util.Timeout; -import io.netty.util.Timer; import io.netty.util.TimerTask; import java.net.InetSocketAddress; import java.util.List; @@ -55,6 +54,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs; import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager; import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider; import org.opendaylight.netconf.client.mdsal.impl.DefaultBaseNetconfSchemas; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; @@ -80,7 +80,7 @@ public class NetconfNodeHandlerTest { // Core setup @Mock - private Timer timer; + private NetconfTimer timer; @Mock private SchemaResourceManager schemaManager; @Mock diff --git a/artifacts/pom.xml b/artifacts/pom.xml index dc5c736477..74175125b0 100644 --- a/artifacts/pom.xml +++ b/artifacts/pom.xml @@ -50,6 +50,11 @@ netconf-client ${project.version} + + ${project.groupId} + netconf-common + ${project.version} + ${project.groupId} netconf-common-mdsal diff --git a/features/odl-netconf-client/pom.xml b/features/odl-netconf-client/pom.xml index 9420362a4e..579f3d85e4 100644 --- a/features/odl-netconf-client/pom.xml +++ b/features/odl-netconf-client/pom.xml @@ -20,12 +20,6 @@ feature - - org.opendaylight.controller - odl-controller-exp-netty-config - xml - features - org.opendaylight.netconf odl-netconf-netty-util diff --git a/features/odl-netconf-client/src/main/feature/feature.xml b/features/odl-netconf-client/src/main/feature/feature.xml deleted file mode 100644 index 8a95fcc95e..0000000000 --- a/features/odl-netconf-client/src/main/feature/feature.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - odl-controller-exp-netty-config - - diff --git a/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/CallHomeTransportChannelListener.java b/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/CallHomeTransportChannelListener.java index af9dd7fe7d..54d9a05768 100644 --- a/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/CallHomeTransportChannelListener.java +++ b/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/CallHomeTransportChannelListener.java @@ -7,8 +7,9 @@ */ package org.opendaylight.netconf.callhome.server; +import static java.util.Objects.requireNonNull; + import io.netty.handler.ssl.SslHandler; -import io.netty.util.concurrent.Promise; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.netconf.client.ClientChannelInitializer; import org.opendaylight.netconf.client.NetconfClientSession; @@ -21,19 +22,19 @@ import org.slf4j.LoggerFactory; public class CallHomeTransportChannelListener implements TransportChannelListener { private static final Logger LOG = LoggerFactory.getLogger(CallHomeTransportChannelListener.class); - final NetconfClientSessionNegotiatorFactory negotiationFactory; - final CallHomeSessionContextManager contextManager; - final CallHomeStatusRecorder statusRecorder; + private final @NonNull NetconfClientSessionNegotiatorFactory negotiationFactory; + private final CallHomeSessionContextManager contextManager; + private final CallHomeStatusRecorder statusRecorder; public CallHomeTransportChannelListener(final NetconfClientSessionNegotiatorFactory negotiationFactory, final CallHomeSessionContextManager contextManager, final CallHomeStatusRecorder statusRecorder) { - this.negotiationFactory = negotiationFactory; - this.contextManager = contextManager; - this.statusRecorder = statusRecorder; + this.negotiationFactory = requireNonNull(negotiationFactory); + this.contextManager = requireNonNull(contextManager); + this.statusRecorder = requireNonNull(statusRecorder); } @Override - public void onTransportChannelEstablished(@NonNull TransportChannel transportChannel) { + public void onTransportChannelEstablished(final TransportChannel transportChannel) { final var channel = transportChannel.channel(); // identify or create session context associated with current connection @@ -48,7 +49,7 @@ public class CallHomeTransportChannelListener implements TransportChannelListene LOG.info("Starting netconf negotiation for context: {}", context); // init NETCONF negotiation - final Promise promise = channel.eventLoop().newPromise(); + final var promise = channel.eventLoop().newPromise(); promise.addListener(ignored -> { final var cause = promise.cause(); if (cause != null) { @@ -72,7 +73,7 @@ public class CallHomeTransportChannelListener implements TransportChannelListene } @Override - public void onTransportChannelFailed(@NonNull Throwable cause) { + public void onTransportChannelFailed(final Throwable cause) { statusRecorder.onTransportChannelFailure(cause); } } diff --git a/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServer.java b/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServer.java index 5bb353137f..5708f5d448 100644 --- a/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServer.java +++ b/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServer.java @@ -8,15 +8,12 @@ package org.opendaylight.netconf.callhome.server.ssh; import static java.util.Objects.requireNonNull; -import static org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES; import com.google.common.annotations.VisibleForTesting; -import io.netty.util.HashedWheelTimer; import java.net.InetAddress; import java.net.SocketAddress; import java.security.PublicKey; import java.util.List; -import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -164,43 +161,43 @@ public final class CallHomeSshServer implements AutoCloseable { return new CallHomeSshServer( toServerParams(address, port), transportStackFactory == null ? defaultTransportStackFactory() : transportStackFactory, - negotiationFactory == null ? defaultNegotiationFactory() : negotiationFactory, + negotiationFactory, contextManager == null ? new CallHomeSshSessionContextManager() : contextManager, authProvider, statusRecorder); } public Builder withAuthProvider(final CallHomeSshAuthProvider newAuthProvider) { - this.authProvider = newAuthProvider; + authProvider = newAuthProvider; return this; } public Builder withSessionContextManager(final CallHomeSshSessionContextManager newContextManager) { - this.contextManager = newContextManager; + contextManager = newContextManager; return this; } public Builder withStatusRecorder(final CallHomeStatusRecorder newStatusRecorder) { - this.statusRecorder = newStatusRecorder; + statusRecorder = newStatusRecorder; return this; } public Builder withAddress(final InetAddress newAddress) { - this.address = newAddress; + address = newAddress; return this; } public Builder withPort(final int newPort) { - this.port = newPort; + port = newPort; return this; } public Builder withTransportStackFactory(final SSHTransportStackFactory newTransportStackFactory) { - this.transportStackFactory = newTransportStackFactory; + transportStackFactory = newTransportStackFactory; return this; } public Builder withNegotiationFactory(final NetconfClientSessionNegotiatorFactory newNegotiationFactory) { - this.negotiationFactory = newNegotiationFactory; + negotiationFactory = newNegotiationFactory; return this; } } @@ -215,9 +212,4 @@ public final class CallHomeSshServer implements AutoCloseable { private static SSHTransportStackFactory defaultTransportStackFactory() { return new SSHTransportStackFactory("ssh-call-home-server", 0); } - - private static NetconfClientSessionNegotiatorFactory defaultNegotiationFactory() { - return new NetconfClientSessionNegotiatorFactory(new HashedWheelTimer(), - Optional.empty(), DEFAULT_TIMEOUT_MILLIS, DEFAULT_CLIENT_CAPABILITIES); - } } diff --git a/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServer.java b/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServer.java index faa210d7d5..4fccee7566 100644 --- a/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServer.java +++ b/netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServer.java @@ -8,12 +8,9 @@ package org.opendaylight.netconf.callhome.server.tls; import static java.util.Objects.requireNonNull; -import static org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES; import io.netty.channel.ChannelOption; -import io.netty.util.HashedWheelTimer; import java.net.InetAddress; -import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -92,52 +89,51 @@ public final class CallHomeTlsServer implements AutoCloseable { bootstrapFactory == null ? defaultBootstrapFactory() : bootstrapFactory, maxConnections == null ? DEFAULT_MAX_CONNECTIONS : maxConnections, timeoutMillis == null ? DEFAULT_TIMEOUT_MILLIS : timeoutMillis, - negotiationFactory == null ? defaultNegotiationFactory() : negotiationFactory, - contextManager, authProvider, statusRecorder); + negotiationFactory, contextManager, authProvider, statusRecorder); } public Builder withSessionContextManager(final CallHomeTlsSessionContextManager newContextManager) { - this.contextManager = newContextManager; + contextManager = newContextManager; return this; } public Builder withAuthProvider(final CallHomeTlsAuthProvider newAuthProvider) { - this.authProvider = newAuthProvider; + authProvider = newAuthProvider; return this; } public Builder withStatusRecorder(final CallHomeStatusRecorder newStatusRecorder) { - this.statusRecorder = newStatusRecorder; + statusRecorder = newStatusRecorder; return this; } public Builder withAddress(final InetAddress newAddress) { - this.address = newAddress; + address = newAddress; return this; } public Builder withPort(final int newPort) { - this.port = newPort; + port = newPort; return this; } public Builder withMaxConnections(final int newMaxConnections) { - this.maxConnections = newMaxConnections; + maxConnections = newMaxConnections; return this; } public Builder withTimeout(final int newTimeoutMillis) { - this.timeoutMillis = newTimeoutMillis; + timeoutMillis = newTimeoutMillis; return this; } public Builder withBootstrapFactory(final BootstrapFactory newBootstrapFactory) { - this.bootstrapFactory = newBootstrapFactory; + bootstrapFactory = newBootstrapFactory; return this; } public Builder withNegotiationFactory(final NetconfClientSessionNegotiatorFactory newNegotiationFactory) { - this.negotiationFactory = newNegotiationFactory; + negotiationFactory = newNegotiationFactory; return this; } } @@ -152,9 +148,4 @@ public final class CallHomeTlsServer implements AutoCloseable { private static BootstrapFactory defaultBootstrapFactory() { return new BootstrapFactory("tls-call-home-server", 0); } - - private static NetconfClientSessionNegotiatorFactory defaultNegotiationFactory() { - return new NetconfClientSessionNegotiatorFactory(new HashedWheelTimer(), - Optional.empty(), DEFAULT_TIMEOUT_MILLIS, DEFAULT_CLIENT_CAPABILITIES); - } } \ No newline at end of file diff --git a/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServerTest.java b/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServerTest.java index 63fdafbb3a..95527aabe6 100644 --- a/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServerTest.java +++ b/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServerTest.java @@ -17,17 +17,15 @@ import static org.mockito.Mockito.verify; import static org.opendaylight.netconf.api.TransportConstants.SSH_SUBSYSTEM; import com.google.common.util.concurrent.SettableFuture; -import io.netty.util.HashedWheelTimer; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; -import java.net.SocketAddress; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.PublicKey; import java.security.SecureRandom; import java.security.spec.RSAKeyGenParameterSpec; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.Nullable; @@ -39,6 +37,8 @@ import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder; import org.opendaylight.netconf.callhome.server.ssh.CallHomeSshAuthSettings.DefaultAuthSettings; import org.opendaylight.netconf.client.NetconfClientSession; import org.opendaylight.netconf.client.NetconfClientSessionListener; +import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.server.NetconfServerSession; import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory; import org.opendaylight.netconf.server.ServerTransportInitializer; @@ -89,24 +89,21 @@ public class CallHomeSshServerTest { final var client4Keys = generateKeyPair(); // Auth provider - final var authProvider = new CallHomeSshAuthProvider() { - @Override - public CallHomeSshAuthSettings provideAuth(final SocketAddress remoteAddress, final PublicKey publicKey) { - // identify client 2 by password (invalid) - if (client2Keys.getPublic().equals(publicKey)) { - return new DefaultAuthSettings("client2-id", USERNAME, Set.of("invalid-password"), null); - } - // identify client 3 by password (valid) - if (client3Keys.getPublic().equals(publicKey)) { - return new DefaultAuthSettings("client3-id", USERNAME, Set.of(PASSWORD), null); - } - // identify client 4 by public key - if (client4Keys.getPublic().equals(publicKey)) { - return new DefaultAuthSettings("client4-id", USERNAME, null, Set.of(serverKeys)); - } - // client 1 is not identified - return null; + final var authProvider = (CallHomeSshAuthProvider) (remoteAddress, publicKey) -> { + // identify client 2 by password (invalid) + if (client2Keys.getPublic().equals(publicKey)) { + return new DefaultAuthSettings("client2-id", USERNAME, Set.of("invalid-password"), null); + } + // identify client 3 by password (valid) + if (client3Keys.getPublic().equals(publicKey)) { + return new DefaultAuthSettings("client3-id", USERNAME, Set.of(PASSWORD), null); } + // identify client 4 by public key + if (client4Keys.getPublic().equals(publicKey)) { + return new DefaultAuthSettings("client4-id", USERNAME, null, Set.of(serverKeys)); + } + // client 1 is not identified + return null; }; // client side authenticators final PasswordAuthenticator passwordAuthenticator = @@ -118,8 +115,10 @@ public class CallHomeSshServerTest { doReturn(serverSessionListener).when(monitoringService).getSessionListener(); doReturn(EMPTY_CAPABILITIES).when(monitoringService).getCapabilities(); + final var timer = new DefaultNetconfTimer(); + final var negotiatorFactory = NetconfServerSessionNegotiatorFactory.builder() - .setTimer(new HashedWheelTimer()) + .setTimer(timer) .setAggregatedOpService(new AggregatedNetconfOperationServiceFactory()) .setIdProvider(new DefaultSessionIdProvider()) .setConnectionTimeoutMillis(TIMEOUT) @@ -138,7 +137,7 @@ public class CallHomeSshServerTest { final var contextManager = new CallHomeSshSessionContextManager() { // inject netconf session listener @Override - public CallHomeSshSessionContext createContext(String id, ClientSession clientSession) { + public CallHomeSshSessionContext createContext(final String id, final ClientSession clientSession) { return new CallHomeSshSessionContext(id, clientSession.getRemoteAddress(), clientSession, clientSessionListener, SettableFuture.create()); } @@ -150,6 +149,8 @@ public class CallHomeSshServerTest { .withAuthProvider(authProvider) .withSessionContextManager(contextManager) .withStatusRecorder(statusRecorder) + .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), TIMEOUT, + NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES)) .build(); SSHServer client1 = null; @@ -211,6 +212,7 @@ public class CallHomeSshServerTest { shutdownClient(client2); shutdownClient(client3); shutdownClient(client4); + timer.close(); } // verify disconnect reported diff --git a/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServerTest.java b/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServerTest.java index 03e2afe41d..4bce3578d0 100644 --- a/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServerTest.java +++ b/netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServerTest.java @@ -20,7 +20,6 @@ import io.netty.channel.Channel; import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; -import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.Promise; import java.math.BigInteger; import java.net.InetAddress; @@ -36,6 +35,7 @@ import java.security.spec.RSAKeyGenParameterSpec; import java.time.Duration; import java.time.Instant; import java.util.Date; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -56,6 +56,8 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder; import org.opendaylight.netconf.client.NetconfClientSession; import org.opendaylight.netconf.client.NetconfClientSessionListener; +import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer; import org.opendaylight.netconf.server.NetconfServerSession; import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory; @@ -120,7 +122,8 @@ public class CallHomeTlsServerTest { // Auth provider final var authProvider = new CallHomeTlsAuthProvider() { @Override - public @Nullable String idFor(@NonNull PublicKey publicKey) { + public @Nullable String idFor(@NonNull + final PublicKey publicKey) { // identify client 3 only return clientCert3.keyPair.getPublic().equals(publicKey) ? "client-id" : null; } @@ -135,8 +138,10 @@ public class CallHomeTlsServerTest { doReturn(serverSessionListener).when(monitoringService).getSessionListener(); doReturn(EMPTY_CAPABILITIES).when(monitoringService).getCapabilities(); + final var timer = new DefaultNetconfTimer(); + final var negotiatorFactory = NetconfServerSessionNegotiatorFactory.builder() - .setTimer(new HashedWheelTimer()) + .setTimer(timer) .setAggregatedOpService(new AggregatedNetconfOperationServiceFactory()) .setIdProvider(new DefaultSessionIdProvider()) .setConnectionTimeoutMillis(TIMEOUT) @@ -165,6 +170,8 @@ public class CallHomeTlsServerTest { .withAuthProvider(authProvider) .withSessionContextManager(contextMgr) .withStatusRecorder(statusRecorder) + .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), TIMEOUT, + NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES)) .withPort(serverPort).build(); TLSServer client1 = null; @@ -200,6 +207,7 @@ public class CallHomeTlsServerTest { shutdownClient(client1); shutdownClient(client2); shutdownClient(client3); + timer.close(); } // validate disconnect reported diff --git a/netconf/netconf-netty-util/pom.xml b/netconf/netconf-netty-util/pom.xml index 928dd18857..c728068cfc 100644 --- a/netconf/netconf-netty-util/pom.xml +++ b/netconf/netconf-netty-util/pom.xml @@ -80,6 +80,10 @@ org.opendaylight.netconf netconf-api + + org.opendaylight.netconf + netconf-common + org.opendaylight.netconf shaded-exificient diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionNegotiator.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionNegotiator.java index 7e2e1fff31..3e16d1fb21 100644 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionNegotiator.java +++ b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionNegotiator.java @@ -18,7 +18,6 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.ssl.SslHandler; import io.netty.util.Timeout; -import io.netty.util.Timer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; import java.util.concurrent.TimeUnit; @@ -34,6 +33,7 @@ import org.opendaylight.netconf.api.NetconfSessionListener; import org.opendaylight.netconf.api.messages.HelloMessage; import org.opendaylight.netconf.api.messages.NetconfMessage; import org.opendaylight.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder; import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator; import org.opendaylight.netconf.nettyutil.handler.NetconfMessageToXMLEncoder; @@ -92,7 +92,7 @@ public abstract class NetconfSessionNegotiator promise; private final L sessionListener; - private final Timer timer; + private final NetconfTimer timer; @GuardedBy("this") private Timeout timeoutTask; @@ -100,12 +100,12 @@ public abstract class NetconfSessionNegotiator promise, final Channel channel, - final Timer timer, final L sessionListener, final long connectionTimeoutMillis, + final NetconfTimer timer, final L sessionListener, final long connectionTimeoutMillis, final @NonNegative int maximumIncomingChunkSize) { localHello = requireNonNull(hello); this.promise = requireNonNull(promise); this.channel = requireNonNull(channel); - this.timer = timer; + this.timer = requireNonNull(timer); this.sessionListener = sessionListener; this.connectionTimeoutMillis = connectionTimeoutMillis; this.maximumIncomingChunkSize = maximumIncomingChunkSize; diff --git a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java index 4e6952f909..323c6aa056 100644 --- a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java +++ b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java @@ -32,7 +32,6 @@ import io.netty.channel.ChannelPromise; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.ssl.SslHandler; import io.netty.util.Timeout; -import io.netty.util.Timer; import io.netty.util.TimerTask; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.Promise; @@ -51,6 +50,7 @@ import org.opendaylight.netconf.api.CapabilityURN; import org.opendaylight.netconf.api.NetconfSessionListener; import org.opendaylight.netconf.api.messages.HelloMessage; import org.opendaylight.netconf.api.xml.XmlUtil; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder; import org.opendaylight.netconf.nettyutil.handler.EOMFramingMechanismEncoder; import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator; @@ -66,7 +66,7 @@ public class AbstractNetconfSessionNegotiatorTest { @Mock private SslHandler sslHandler; @Mock - private Timer timer; + private NetconfTimer timer; @Mock private Timeout timeout; private EmbeddedChannel channel; diff --git a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java index c6353662f9..20690f7fad 100644 --- a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java +++ b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java @@ -14,7 +14,6 @@ import static org.opendaylight.netconf.nettyutil.AbstractChannelInitializer.NETC import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.embedded.EmbeddedChannel; -import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.Promise; import java.util.Optional; import java.util.Set; @@ -26,6 +25,7 @@ import org.mockito.junit.MockitoJUnitRunner; import org.opendaylight.netconf.api.CapabilityURN; import org.opendaylight.netconf.api.NetconfSessionListener; import org.opendaylight.netconf.api.messages.HelloMessage; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder; import org.opendaylight.netconf.nettyutil.handler.EOMFramingMechanismEncoder; import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator; @@ -55,7 +55,8 @@ public class Netconf539Test { channel.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfEOMAggregator()); final HelloMessage serverHello = HelloMessage.createClientHello(Set.of(CapabilityURN.BASE_1_1), Optional.empty()); - negotiator = new TestSessionNegotiator(serverHello, promise, channel, new HashedWheelTimer(), listener, 100L); + negotiator = new TestSessionNegotiator(serverHello, promise, channel, new DefaultNetconfTimer(), listener, + 100L); } @Test diff --git a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestSessionNegotiator.java b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestSessionNegotiator.java index d7bcb1525e..4af6b430af 100644 --- a/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestSessionNegotiator.java +++ b/netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestSessionNegotiator.java @@ -8,17 +8,17 @@ package org.opendaylight.netconf.nettyutil; import io.netty.channel.Channel; -import io.netty.util.Timer; import io.netty.util.concurrent.Promise; import org.opendaylight.netconf.api.NetconfSessionListener; import org.opendaylight.netconf.api.messages.HelloMessage; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType; import org.opendaylight.yangtools.yang.common.Uint32; final class TestSessionNegotiator extends NetconfSessionNegotiator> { TestSessionNegotiator(final HelloMessage hello, final Promise promise, - final Channel channel, final Timer timer, + final Channel channel, final NetconfTimer timer, final NetconfSessionListener sessionListener, final long connectionTimeoutMillis) { super(hello, promise, channel, timer, sessionListener, connectionTimeoutMillis, 16384); } diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/NetconfDeviceSimulator.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/NetconfDeviceSimulator.java index 33c4d9c0fc..1e2a200293 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/NetconfDeviceSimulator.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/NetconfDeviceSimulator.java @@ -12,7 +12,6 @@ import static java.util.Objects.requireNonNullElseGet; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.Futures; -import io.netty.util.HashedWheelTimer; import java.io.Closeable; import java.io.IOException; import java.net.InetAddress; @@ -27,6 +26,7 @@ import java.util.concurrent.ExecutionException; import java.util.stream.IntStream; import org.opendaylight.netconf.api.CapabilityURN; import org.opendaylight.netconf.api.TransportConstants; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.server.ServerTransportInitializer; import org.opendaylight.netconf.server.api.SessionIdProvider; import org.opendaylight.netconf.server.api.monitoring.BasicCapability; @@ -77,7 +77,7 @@ import org.slf4j.LoggerFactory; public class NetconfDeviceSimulator implements Closeable { private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSimulator.class); - private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(); + private final DefaultNetconfTimer timer = new DefaultNetconfTimer(); private final Configuration configuration; private final List servers; private final SSHTransportStackFactory sshStackFactory; @@ -109,8 +109,8 @@ public class NetconfDeviceSimulator implements Closeable { final var aggregatedNetconfOperationServiceFactory = createOperationServiceFactory( sourceProvider, transformedCapabilities, monitoringService1, idProvider); - return new ServerTransportInitializer(new TesttoolNegotiationFactory( - hashedWheelTimer, aggregatedNetconfOperationServiceFactory, idProvider, + return new ServerTransportInitializer(new TesttoolNegotiationFactory(timer, + aggregatedNetconfOperationServiceFactory, idProvider, configuration.getGenerateConfigsTimeout(), monitoringService1, configuration.getCapabilities())); } diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolNegotiationFactory.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolNegotiationFactory.java index e26db5e404..4ce4df4ce2 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolNegotiationFactory.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolNegotiationFactory.java @@ -7,11 +7,11 @@ */ package org.opendaylight.netconf.test.tool; -import io.netty.util.Timer; import java.net.SocketAddress; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory; import org.opendaylight.netconf.server.api.SessionIdProvider; import org.opendaylight.netconf.server.api.monitoring.NetconfMonitoringService; @@ -26,16 +26,17 @@ public class TesttoolNegotiationFactory extends NetconfServerSessionNegotiatorFa private final ConcurrentMap operationServices = new ConcurrentHashMap<>(); - public TesttoolNegotiationFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider, - final SessionIdProvider idProvider, final long connectionTimeoutMillis, - final NetconfMonitoringService monitoringService) { + public TesttoolNegotiationFactory(final NetconfTimer timer, + final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider, + final long connectionTimeoutMillis, final NetconfMonitoringService monitoringService) { super(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, monitoringService, NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES); } - public TesttoolNegotiationFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider, - final SessionIdProvider idProvider, final long connectionTimeoutMillis, - final NetconfMonitoringService monitoringService, final Set baseCapabilities) { + public TesttoolNegotiationFactory(final NetconfTimer timer, + final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider, + final long connectionTimeoutMillis, final NetconfMonitoringService monitoringService, + final Set baseCapabilities) { super(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, monitoringService, baseCapabilities); } diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClient.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClient.java index 9b1c30d244..ed2b31a742 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClient.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClient.java @@ -30,6 +30,7 @@ import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder; import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator; import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences; import org.opendaylight.netconf.client.mdsal.api.RemoteDevice; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.test.tool.TestToolUtils; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.CommitInput; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.EditConfigInput; @@ -165,29 +166,30 @@ public final class StressClient { } } - final var netconfClientFactory = new NetconfClientFactoryImpl(); + try (var timer = new DefaultNetconfTimer()) { + try (var netconfClientFactory = new NetconfClientFactoryImpl(timer)) { - final var callables = new ArrayList(threadAmount); - for (var messages : allPreparedMessages) { - callables.add(new StressClientCallable(params, netconfClientFactory, getBaseConfiguration(), messages)); - } - - final var executorService = Executors.newFixedThreadPool(threadAmount); + final var callables = new ArrayList(threadAmount); + for (var messages : allPreparedMessages) { + callables.add(new StressClientCallable(params, netconfClientFactory, getBaseConfiguration(), + messages)); + } - LOG.info("Starting stress test"); - final var sw = Stopwatch.createStarted(); - final var futures = executorService.invokeAll(callables); - for (var future : futures) { - future.get(4L, TimeUnit.MINUTES); - } - executorService.shutdownNow(); - sw.stop(); + final var executorService = Executors.newFixedThreadPool(threadAmount); - LOG.info("FINISHED. Execution time: {}", sw); - LOG.info("Requests per second: {}", params.editCount * 1000.0 / sw.elapsed(TimeUnit.MILLISECONDS)); + LOG.info("Starting stress test"); + final var sw = Stopwatch.createStarted(); + final var futures = executorService.invokeAll(callables); + for (var future : futures) { + future.get(4L, TimeUnit.MINUTES); + } + executorService.shutdownNow(); + sw.stop(); - // Cleanup - netconfClientFactory.close(); + LOG.info("FINISHED. Execution time: {}", sw); + LOG.info("Requests per second: {}", params.editCount * 1000.0 / sw.elapsed(TimeUnit.MILLISECONDS)); + } + } } static NetconfMessage prepareMessage(final int id, final String editContentString) { diff --git a/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java b/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java index f16bf76611..3b25a01273 100644 --- a/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java +++ b/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java @@ -36,6 +36,7 @@ import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener; import org.opendaylight.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol; import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.test.tool.config.Configuration; import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.password.grouping.password.type.CleartextPasswordBuilder; @@ -101,6 +102,7 @@ public class TestToolTest { "ncmon", "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring" ); + private static DefaultNetconfTimer timer; private static NetconfClientFactory clientFactory; private static NetconfDeviceSimulator tcpDeviceSimulator; private static NetconfDeviceSimulator sshDeviceSimulator; @@ -109,7 +111,8 @@ public class TestToolTest { @BeforeAll static void beforeAll() { - clientFactory = new NetconfClientFactoryImpl(); + timer = new DefaultNetconfTimer(); + clientFactory = new NetconfClientFactoryImpl(timer); tcpDeviceSimulator = new NetconfDeviceSimulator(getSimulatorConfig(TCP)); tcpDevicePort = startSimulator(tcpDeviceSimulator); sshDeviceSimulator = new NetconfDeviceSimulator(getSimulatorConfig(SSH)); @@ -123,6 +126,7 @@ public class TestToolTest { stopSimulator(sshDeviceSimulator); sshDeviceSimulator = null; clientFactory.close(); + timer.close(); } @ParameterizedTest(name = "Custom RPC -- RFC7950 {0}") diff --git a/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacade.java b/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacade.java index 833c80c9f5..d9551a7b02 100644 --- a/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacade.java +++ b/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacade.java @@ -19,7 +19,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import io.netty.util.Timeout; -import io.netty.util.Timer; import io.netty.util.TimerTask; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; @@ -37,6 +36,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs; import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.GetConfig; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; @@ -60,7 +60,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler { private final RemoteDeviceHandler deviceHandler; private final RemoteDeviceId deviceId; - private final Timer timer; + private final NetconfTimer timer; private final long keepaliveDelaySeconds; private final long timeoutNanos; private final long delayNanos; @@ -68,8 +68,8 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler { private volatile NetconfDeviceCommunicator listener; private volatile KeepaliveTask task; - public KeepaliveSalFacade(final RemoteDeviceId deviceId, final RemoteDeviceHandler deviceHandler, final Timer timer, - final long keepaliveDelaySeconds, final long requestTimeoutMillis) { + public KeepaliveSalFacade(final RemoteDeviceId deviceId, final RemoteDeviceHandler deviceHandler, + final NetconfTimer timer, final long keepaliveDelaySeconds, final long requestTimeoutMillis) { this.deviceId = requireNonNull(deviceId); this.deviceHandler = requireNonNull(deviceHandler); this.timer = requireNonNull(timer); @@ -79,7 +79,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler { } public KeepaliveSalFacade(final RemoteDeviceId deviceId, final RemoteDeviceHandler deviceHandler, - final Timer timer) { + final NetconfTimer timer) { this(deviceId, deviceHandler, timer, DEFAULT_DELAY, DEFAULT_TRANSACTION_TIMEOUT_MILLI); } diff --git a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeResponseWaitingTest.java b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeResponseWaitingTest.java index f1f1a5fa2f..b6fe782770 100644 --- a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeResponseWaitingTest.java +++ b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeResponseWaitingTest.java @@ -13,8 +13,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import com.google.common.util.concurrent.SettableFuture; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; import java.net.InetSocketAddress; import org.eclipse.jdt.annotation.NonNull; import org.junit.jupiter.api.AfterEach; @@ -35,6 +33,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs; import org.opendaylight.netconf.client.mdsal.impl.NetconfBaseOps; import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.GetConfig; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; @@ -52,14 +51,14 @@ class KeepaliveSalFacadeResponseWaitingTest { private Rpcs.Normalized deviceRpc; @Mock private NetconfDeviceCommunicator listener; - private Timer timer; + private DefaultNetconfTimer timer; private KeepaliveSalFacade keepaliveSalFacade; private LocalNetconfSalFacade underlyingSalFacade; @BeforeEach void beforeEach() { - timer = new HashedWheelTimer(); + timer = new DefaultNetconfTimer(); underlyingSalFacade = new LocalNetconfSalFacade(); keepaliveSalFacade = new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, timer, 2L, 10000L); @@ -68,7 +67,7 @@ class KeepaliveSalFacadeResponseWaitingTest { @AfterEach void afterEach() { - timer.stop(); + timer.close(); } /** diff --git a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeTest.java b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeTest.java index cd17b63829..cc438d0ce1 100644 --- a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeTest.java +++ b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeTest.java @@ -21,8 +21,6 @@ import static org.mockito.Mockito.verify; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.SettableFuture; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; import java.net.InetSocketAddress; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -37,6 +35,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices; import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs; import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; @@ -54,20 +53,20 @@ class KeepaliveSalFacadeTest { @Mock private Rpcs.Normalized deviceRpc; - private Timer timer; + private DefaultNetconfTimer timer; private KeepaliveSalFacade keepaliveSalFacade; private Rpcs proxyRpc; @BeforeEach void beforeEach() { - timer = new HashedWheelTimer(); + timer = new DefaultNetconfTimer(); keepaliveSalFacade = new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, timer, 1L, 1L); keepaliveSalFacade.setListener(listener); } @AfterEach void afterEach() { - timer.stop(); + timer.close(); } @Test diff --git a/protocol/netconf-client/pom.xml b/protocol/netconf-client/pom.xml index 6484baa0e1..5cd445aba1 100644 --- a/protocol/netconf-client/pom.xml +++ b/protocol/netconf-client/pom.xml @@ -51,6 +51,12 @@ io.netty netty-transport + + jakarta.annotation + jakarta.annotation-api + provided + true + org.checkerframework checker-qual diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java index b9c5de2667..9f86a1a660 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java @@ -15,11 +15,11 @@ import static org.opendaylight.netconf.client.conf.NetconfClientConfiguration.Ne import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; +import javax.annotation.PreDestroy; import javax.inject.Singleton; import org.opendaylight.netconf.api.TransportConstants; import org.opendaylight.netconf.client.conf.NetconfClientConfiguration; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.transport.api.TransportChannel; import org.opendaylight.netconf.transport.api.TransportChannelListener; import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException; @@ -30,27 +30,30 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types. import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; @Singleton +// FIXME: drop the property and use lazy activation @Component(immediate = true, service = NetconfClientFactory.class, property = "type=netconf-client-factory") public class NetconfClientFactoryImpl implements NetconfClientFactory { - private final Timer timer = new HashedWheelTimer(); private final SSHTransportStackFactory factory; + private final NetconfTimer timer; - @Activate - public NetconfClientFactoryImpl() { - // TODO make factory component configurable for osgi - this(new SSHTransportStackFactory("odl-netconf-client", 0)); + public NetconfClientFactoryImpl(final NetconfTimer timer, final SSHTransportStackFactory factory) { + this.timer = requireNonNull(timer); + this.factory = requireNonNull(factory); } - public NetconfClientFactoryImpl(final SSHTransportStackFactory factory) { - this.factory = requireNonNull(factory); + @Activate + public NetconfClientFactoryImpl(@Reference final NetconfTimer timer) { + // FIXME: make factory component configurable for OSGi + this(timer, new SSHTransportStackFactory("odl-netconf-client", 0)); } + @PreDestroy @Deactivate @Override public void close() { - timer.stop(); factory.close(); } diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java index beb9282ba9..8455821ef5 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java @@ -15,7 +15,6 @@ import com.google.common.collect.Interners; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.util.Timer; import io.netty.util.concurrent.Promise; import java.util.Set; import javax.xml.xpath.XPathConstants; @@ -29,6 +28,7 @@ import org.opendaylight.netconf.api.messages.NetconfMessage; import org.opendaylight.netconf.api.messages.RpcMessage; import org.opendaylight.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.netconf.api.xml.XmlUtil; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer; import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType; @@ -57,7 +57,7 @@ class NetconfClientSessionNegotiator private final RpcMessage startExi; NetconfClientSessionNegotiator(final HelloMessage hello, final RpcMessage startExi, - final Promise promise, final Channel channel, final Timer timer, + final Promise promise, final Channel channel, final NetconfTimer timer, final NetconfClientSessionListener sessionListener, final long connectionTimeoutMillis, final @NonNegative int maximumIncomingChunkSize) { super(hello, promise, channel, timer, sessionListener, connectionTimeoutMillis, maximumIncomingChunkSize); @@ -206,10 +206,9 @@ class NetconfClientSessionNegotiator // Unexpected response to start-exi, throwing message away, continue without exi } else { - LOG.warn("Unexpected response to start-exi message, should be ok, was {}, " - + "Communication will continue without exi " - + "and response message will be thrown away on session {}", - netconfMessage, session); + LOG.warn(""" + Unexpected response to start-exi message, should be ok, was {}. Communication will continue \ + without EXI and response message will be thrown away on session {}""", netconfMessage, session); } negotiationSuccessful(session); diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactory.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactory.java index d49d3a2684..7b2f464b44 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactory.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactory.java @@ -11,7 +11,6 @@ import static java.util.Objects.requireNonNull; import com.google.common.collect.ImmutableSet; import io.netty.channel.Channel; -import io.netty.util.Timer; import io.netty.util.concurrent.Promise; import java.util.Optional; import java.util.Set; @@ -20,6 +19,7 @@ import org.opendaylight.netconf.api.CapabilityURN; import org.opendaylight.netconf.api.NetconfSessionListenerFactory; import org.opendaylight.netconf.api.messages.HelloMessage; import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator; import org.opendaylight.netconf.nettyutil.handler.exi.EXIParameters; import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessageProvider; @@ -66,16 +66,16 @@ public final class NetconfClientSessionNegotiatorFactory { private final @NonNegative int maximumIncomingChunkSize; private final Set clientCapabilities; private final long connectionTimeoutMillis; - private final Timer timer; + private final NetconfTimer timer; private final EXIParameters options; - public NetconfClientSessionNegotiatorFactory(final Timer timer, + public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer, final Optional additionalHeader, final long connectionTimeoutMillis) { this(timer, additionalHeader, connectionTimeoutMillis, DEFAULT_OPTIONS); } - public NetconfClientSessionNegotiatorFactory(final Timer timer, + public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer, final Optional additionalHeader, final long connectionTimeoutMillis, final @NonNegative int maximumIncomingChunkSize) { @@ -83,20 +83,20 @@ public final class NetconfClientSessionNegotiatorFactory { maximumIncomingChunkSize); } - public NetconfClientSessionNegotiatorFactory(final Timer timer, + public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer, final Optional additionalHeader, final long connectionTimeoutMillis, final Set capabilities) { this(timer, additionalHeader, connectionTimeoutMillis, DEFAULT_OPTIONS, capabilities); } - public NetconfClientSessionNegotiatorFactory(final Timer timer, + public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer, final Optional additionalHeader, final long connectionTimeoutMillis, final EXIParameters exiOptions) { this(timer, additionalHeader, connectionTimeoutMillis, exiOptions, EXI_CLIENT_CAPABILITIES); } - public NetconfClientSessionNegotiatorFactory(final Timer timer, + public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer, final Optional additionalHeader, final long connectionTimeoutMillis, final EXIParameters exiOptions, final Set capabilities) { @@ -104,7 +104,7 @@ public final class NetconfClientSessionNegotiatorFactory { NetconfSessionNegotiator.DEFAULT_MAXIMUM_INCOMING_CHUNK_SIZE); } - public NetconfClientSessionNegotiatorFactory(final Timer timer, + public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer, final Optional additionalHeader, final long connectionTimeoutMillis, final EXIParameters exiOptions, final Set capabilities, diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java index 26993e1fcb..142009b7ba 100644 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java +++ b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java @@ -46,6 +46,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.opendaylight.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.shaded.sshd.client.auth.password.PasswordIdentityProvider; import org.opendaylight.netconf.shaded.sshd.server.auth.password.UserAuthPasswordFactory; import org.opendaylight.netconf.shaded.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; @@ -91,7 +92,8 @@ class NetconfClientFactoryImplTest { private static final String RSA = "RSA"; private static final char[] EMPTY_SECRET = new char[0]; - private static SSHTransportStackFactory serverTransportFactory; + private static SSHTransportStackFactory SERVER_FACTORY; + private static DefaultNetconfTimer TIMER; @Mock private NetconfClientSessionListener sessionListener; @@ -104,20 +106,21 @@ class NetconfClientFactoryImplTest { private TcpServerGrouping tcpServerParams; private TcpClientGrouping tcpClientParams; - @BeforeAll static void beforeAll() { - serverTransportFactory = new SSHTransportStackFactory("server", 0); + SERVER_FACTORY = new SSHTransportStackFactory("server", 0); + TIMER = new DefaultNetconfTimer(); } @AfterAll static void afterAll() { - serverTransportFactory.close(); + SERVER_FACTORY.close(); + TIMER.close(); } @BeforeEach void beforeEach() throws Exception { - factory = new NetconfClientFactoryImpl(); + factory = new NetconfClientFactoryImpl(TIMER); doNothing().when(serverTransportListener).onTransportChannelEstablished(any()); // create temp socket to get available port for test @@ -141,7 +144,7 @@ class NetconfClientFactoryImplTest { @Test void tcpClient() throws Exception { final var server = TCPServer.listen(serverTransportListener, - serverTransportFactory.newServerBootstrap(), tcpServerParams).get(1, TimeUnit.SECONDS); + SERVER_FACTORY.newServerBootstrap(), tcpServerParams).get(1, TimeUnit.SECONDS); try { final var clientConfig = NetconfClientConfigurationBuilder.create() .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TCP) @@ -164,7 +167,7 @@ class NetconfClientFactoryImplTest { final var serverContext = SslContextBuilder.forServer(keyMgr).trustManager(trustMgr).build(); final var clientContext = SslContextBuilder.forClient().keyManager(keyMgr).trustManager(trustMgr).build(); - final var server = TLSServer.listen(serverTransportListener, serverTransportFactory.newServerBootstrap(), + final var server = TLSServer.listen(serverTransportListener, SERVER_FACTORY.newServerBootstrap(), tcpServerParams, channel -> serverContext.newHandler(channel.alloc())).get(1, TimeUnit.SECONDS); try { final var clientConfig = NetconfClientConfigurationBuilder.create() @@ -211,7 +214,7 @@ class NetconfClientFactoryImplTest { doReturn(null).when(sshServerParams).getTransportParams(); doReturn(null).when(sshServerParams).getKeepalives(); - final var server = serverTransportFactory.listenServer("netconf", serverTransportListener, tcpServerParams, + final var server = SERVER_FACTORY.listenServer("netconf", serverTransportListener, tcpServerParams, sshServerParams).get(10, TimeUnit.SECONDS); try { @@ -278,7 +281,7 @@ class NetconfClientFactoryImplTest { new org.opendaylight.netconf.shaded.sshd.client.auth.password.UserAuthPasswordFactory())); }; - final var server = serverTransportFactory.listenServer("netconf", serverTransportListener, tcpServerParams, + final var server = SERVER_FACTORY.listenServer("netconf", serverTransportListener, tcpServerParams, null, serverConfigurator).get(10, TimeUnit.SECONDS); try { final var clientConfig = NetconfClientConfigurationBuilder.create() diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactoryTest.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactoryTest.java index 34fa1f3256..cab7ec382a 100644 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactoryTest.java +++ b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactoryTest.java @@ -12,18 +12,17 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import io.netty.channel.Channel; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; import io.netty.util.concurrent.Promise; import java.util.Optional; import org.junit.Test; import org.opendaylight.netconf.api.NetconfSessionListenerFactory; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; public class NetconfClientSessionNegotiatorFactoryTest { @Test public void testGetSessionNegotiator() throws Exception { NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class); - Timer timer = new HashedWheelTimer(); + final var timer = new DefaultNetconfTimer(); NetconfSessionListenerFactory listenerFactory = mock(NetconfSessionListenerFactory.class); doReturn(sessionListener).when(listenerFactory).getSessionListener(); diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorTest.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorTest.java index 9d8a0a72a9..ffb32f353b 100644 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorTest.java +++ b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorTest.java @@ -29,8 +29,6 @@ import io.netty.channel.ChannelPromise; import io.netty.channel.EventLoop; import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.ssl.SslHandler; -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.Promise; import java.io.InputStream; @@ -42,6 +40,7 @@ import org.opendaylight.netconf.api.messages.HelloMessage; import org.opendaylight.netconf.api.messages.NetconfMessage; import org.opendaylight.netconf.api.messages.RpcMessage; import org.opendaylight.netconf.api.xml.XmlUtil; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder; import org.opendaylight.netconf.nettyutil.handler.NetconfEXIToMessageDecoder; import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToHelloMessageDecoder; @@ -133,7 +132,7 @@ public class NetconfClientSessionNegotiatorTest { long timeout = 10L; NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class); - Timer timer = new HashedWheelTimer(); + var timer = new DefaultNetconfTimer(); return new NetconfClientSessionNegotiator(helloMessage, startExi, promise, channel, timer, sessionListener, timeout, 16384); } diff --git a/protocol/netconf-common/pom.xml b/protocol/netconf-common/pom.xml new file mode 100644 index 0000000000..153d2a8a78 --- /dev/null +++ b/protocol/netconf-common/pom.xml @@ -0,0 +1,57 @@ + + + + 4.0.0 + + + org.opendaylight.netconf + netconf-parent + 7.0.0-SNAPSHOT + ../../parent + + + netconf-common + ${project.artifactId} + bundle + Shared NETCONF protocol components + + + + com.google.guava + guava + + + com.guicedee.services + javax.inject + true + + + io.netty + netty-common + + + jakarta.annotation + jakarta.annotation-api + provided + true + + + org.eclipse.jdt + org.eclipse.jdt.annotation + + + org.osgi + org.osgi.service.component.annotations + + + org.osgi + org.osgi.service.metatype.annotations + + + diff --git a/protocol/netconf-common/src/main/java/module-info.java b/protocol/netconf-common/src/main/java/module-info.java new file mode 100644 index 0000000000..30f56e8344 --- /dev/null +++ b/protocol/netconf-common/src/main/java/module-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +module org.opendaylight.netconf.common { + exports org.opendaylight.netconf.common; + exports org.opendaylight.netconf.common.impl; + + requires transitive io.netty.common; + requires com.google.common; + requires org.slf4j; + + // Annotation-only dependencies + requires static transitive java.annotation; + requires static transitive javax.inject; + requires static transitive org.eclipse.jdt.annotation; + requires static org.osgi.service.component.annotations; + requires static org.osgi.service.metatype.annotations; +} diff --git a/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/NetconfTimer.java b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/NetconfTimer.java new file mode 100644 index 0000000000..2abb3e783c --- /dev/null +++ b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/NetconfTimer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.netconf.common; + +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * A NETCONF-specific equivalent of {@link Timer}. It specifically excludes {@link Timer#stop()} from the API surface. + */ +@NonNullByDefault +public interface NetconfTimer { + /** + * Schedules the specified {@link TimerTask} for one-time execution after the specified delay. + * See {@link Timer#newTimeout(TimerTask, long, TimeUnit)}. + * + * @param task a TimerTask + * @param delay delay to apply + * @param unit a TimeUnit + * @return a handle which is associated with the specified task + * @throws NullPointerException if any argument is {@code null} + * @throws IllegalStateException if this timer has been stopped already + * @throws RejectedExecutionException if the pending timeouts are too many and creating new timeout can cause + * instability in the system + */ + Timeout newTimeout(TimerTask task, long delay, TimeUnit unit); +} diff --git a/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/impl/DefaultNetconfTimer.java b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/impl/DefaultNetconfTimer.java new file mode 100644 index 0000000000..213e9842c2 --- /dev/null +++ b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/impl/DefaultNetconfTimer.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.netconf.common.impl; + +import static java.util.Objects.requireNonNull; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import javax.annotation.PreDestroy; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.opendaylight.netconf.common.NetconfTimer; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Default {@link NetconfTimer}, delegating to a {@link HashedWheelTimer}. + */ +@Singleton +@Component(service = NetconfTimer.class, configurationPid = "org.opendaylight.netconf.timer") +@Designate(ocd = DefaultNetconfTimer.Configuration.class) +public final class DefaultNetconfTimer implements NetconfTimer, AutoCloseable { + /** + * Configuration of {@link DefaultNetconfTimer}. + */ + @ObjectClassDefinition + public @interface Configuration { + /** + * Return the duration of each timer tick in milliseconds. + * + * @return the duration of each timer tick in milliseconds + */ + @AttributeDefinition(description = "Duration of each timer tick in milliseconds", min = "1") + long tick$_$duration$_$_millis() default 100; + + /** + * Return the size of the timer wheel. + * + * @return the size of the timer wheel + */ + @AttributeDefinition(description = "The size of the timer wheel", min = "1", max = "1073741824") + int ticks$_$per$_$wheel() default 512; + } + + private static final Logger LOG = LoggerFactory.getLogger(DefaultNetconfTimer.class); + private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder() + .setNameFormat("netconf-timer-%d") + .setDaemon(true) + .build(); + + private HashedWheelTimer delegate; + + /** + * Default constructor. Uses default values for both tick duration and wheel size. + */ + @Inject + public DefaultNetconfTimer() { + this(100, TimeUnit.MILLISECONDS, 512); + } + + /** + * Low-level constructor. + * + * @param tickDuration the duration between tick + * @param unit the time unit of the {@code tickDuration} + * @param ticksPerWheel the size of the wheel + */ + public DefaultNetconfTimer(final long tickDuration, final TimeUnit unit, final int ticksPerWheel) { + delegate = new HashedWheelTimer(THREAD_FACTORY, tickDuration, unit, ticksPerWheel); + LOG.info("NETCONF timer started"); + } + + /** + * OSGi constructor. Uses values from supplied {@link Configuration}. + * + * @param config the configuration + */ + @Activate + public DefaultNetconfTimer(final Configuration config) { + this(config.tick$_$duration$_$_millis(), TimeUnit.MILLISECONDS, config.ticks$_$per$_$wheel()); + } + + @Override + public Timeout newTimeout(final TimerTask task, final long delay, final TimeUnit unit) { + final var local = delegate; + if (local == null) { + throw new IllegalStateException("Timer has already been stopped"); + } + return local.newTimeout(requireNonNull(task), delay, requireNonNull(unit)); + } + + @Deactivate + @PreDestroy + @Override + public void close() { + if (delegate != null) { + delegate.stop(); + delegate = null; + LOG.info("NETCONF timer started"); + } + } +} diff --git a/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/package-info.java b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/package-info.java new file mode 100644 index 0000000000..66034ade53 --- /dev/null +++ b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +/** + * Components shared between NETCONF client and NETCONF server. + */ +package org.opendaylight.netconf.common; \ No newline at end of file diff --git a/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiator.java b/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiator.java index 01cb0e6a9f..3fe894a689 100644 --- a/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiator.java +++ b/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiator.java @@ -11,7 +11,6 @@ import static java.util.Objects.requireNonNull; import io.netty.channel.Channel; import io.netty.channel.local.LocalAddress; -import io.netty.util.Timer; import io.netty.util.concurrent.Promise; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -22,6 +21,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.netconf.api.NetconfDocumentedException; import org.opendaylight.netconf.api.messages.HelloMessage; import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType; import org.slf4j.Logger; @@ -35,7 +35,7 @@ public final class NetconfServerSessionNegotiator private final @NonNull SessionIdType sessionId; NetconfServerSessionNegotiator(final HelloMessage hello, final SessionIdType sessionId, - final Promise promise, final Channel channel, final Timer timer, + final Promise promise, final Channel channel, final NetconfTimer timer, final NetconfServerSessionListener sessionListener, final long connectionTimeoutMillis, final @NonNegative int maximumIncomingChunkSize) { super(hello, promise, channel, timer, sessionListener, connectionTimeoutMillis, diff --git a/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiatorFactory.java b/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiatorFactory.java index 444533c3ca..5e32aaa55c 100644 --- a/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiatorFactory.java +++ b/protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiatorFactory.java @@ -13,7 +13,6 @@ import static java.util.Objects.requireNonNull; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import io.netty.channel.Channel; -import io.netty.util.Timer; import io.netty.util.concurrent.Promise; import java.net.SocketAddress; import java.util.HashSet; @@ -22,6 +21,7 @@ import org.checkerframework.checker.index.qual.NonNegative; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.netconf.api.CapabilityURN; import org.opendaylight.netconf.api.messages.HelloMessage; +import org.opendaylight.netconf.common.NetconfTimer; import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator; import org.opendaylight.netconf.server.api.SessionIdProvider; import org.opendaylight.netconf.server.api.monitoring.NetconfMonitoringService; @@ -32,21 +32,21 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.re // non-final for testing and netconf-testtool (for some reason) public class NetconfServerSessionNegotiatorFactory { - public static final Set DEFAULT_BASE_CAPABILITIES = ImmutableSet.of( + public static final ImmutableSet DEFAULT_BASE_CAPABILITIES = ImmutableSet.of( CapabilityURN.BASE, CapabilityURN.BASE_1_1, CapabilityURN.EXI, CapabilityURN.NOTIFICATION); private final @NonNegative int maximumIncomingChunkSize; - private final Timer timer; + private final NetconfTimer timer; private final SessionIdProvider idProvider; private final NetconfOperationServiceFactory aggregatedOpService; private final long connectionTimeoutMillis; private final NetconfMonitoringService monitoringService; private final Set baseCapabilities; - protected NetconfServerSessionNegotiatorFactory(final Timer timer, + protected NetconfServerSessionNegotiatorFactory(final NetconfTimer timer, final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider, final long connectionTimeoutMillis, final NetconfMonitoringService monitoringService, final Set baseCapabilities) { @@ -54,11 +54,11 @@ public class NetconfServerSessionNegotiatorFactory { NetconfSessionNegotiator.DEFAULT_MAXIMUM_INCOMING_CHUNK_SIZE); } - private NetconfServerSessionNegotiatorFactory(final Timer timer, + private NetconfServerSessionNegotiatorFactory(final NetconfTimer timer, final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider, final long connectionTimeoutMillis, final NetconfMonitoringService monitoringService, final Set baseCapabilities, final @NonNegative int maximumIncomingChunkSize) { - this.timer = timer; + this.timer = requireNonNull(timer); aggregatedOpService = netconfOperationProvider; this.idProvider = idProvider; this.connectionTimeoutMillis = connectionTimeoutMillis; @@ -124,7 +124,7 @@ public class NetconfServerSessionNegotiatorFactory { public static final class Builder { private @NonNegative int maximumIncomingChunkSize = NetconfSessionNegotiator.DEFAULT_MAXIMUM_INCOMING_CHUNK_SIZE; - private Timer timer; + private NetconfTimer timer; private SessionIdProvider idProvider; private NetconfOperationServiceFactory aggregatedOpService; private long connectionTimeoutMillis; @@ -135,8 +135,8 @@ public class NetconfServerSessionNegotiatorFactory { // Hidden on purpose } - public Builder setTimer(final Timer timer) { - this.timer = timer; + public Builder setTimer(final NetconfTimer timer) { + this.timer = requireNonNull(timer); return this; } diff --git a/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java b/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java index 74f3e2e5ec..1922cd675c 100644 --- a/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java +++ b/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java @@ -17,7 +17,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.lenient; import static org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES; -import io.netty.util.HashedWheelTimer; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; @@ -36,7 +35,6 @@ import java.util.concurrent.atomic.AtomicLong; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -53,6 +51,7 @@ import org.opendaylight.netconf.client.NetconfClientFactoryImpl; import org.opendaylight.netconf.client.NetconfMessageUtil; import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener; import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder; +import org.opendaylight.netconf.common.impl.DefaultNetconfTimer; import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessageProvider; import org.opendaylight.netconf.server.api.SessionIdProvider; import org.opendaylight.netconf.server.api.monitoring.Capability; @@ -103,11 +102,11 @@ public class ConcurrentClientsTest { private static int serverPort; private static TcpServerGrouping serverParams; private static TcpClientGrouping clientParams; + private static DefaultNetconfTimer timer; private static NetconfMessage getConfigMessage; private static NetconfMessage clientHelloMessage; - private HashedWheelTimer hashedWheelTimer; private BootstrapFactory serverBootstrapFactory; private NetconfClientFactory clientFactory; private TCPServer server; @@ -120,6 +119,7 @@ public class ConcurrentClientsTest { @BeforeAll public static void beforeAll() throws Exception { + timer = new DefaultNetconfTimer(); clientExecutor = Executors.newFixedThreadPool(CONCURRENCY, new ThreadFactory() { int index = 1; @@ -151,11 +151,7 @@ public class ConcurrentClientsTest { @AfterAll static void afterAll() { clientExecutor.shutdownNow(); - } - - @BeforeEach - void beforeEach() { - hashedWheelTimer = new HashedWheelTimer(); + timer.close(); } void startServer(final int threads, final Set serverCapabilities) throws Exception { @@ -175,7 +171,7 @@ public class ConcurrentClientsTest { serverBootstrapFactory = new BootstrapFactory("server", threads); server = TCPServer.listen(new ServerTransportInitializer(NetconfServerSessionNegotiatorFactory.builder() - .setTimer(hashedWheelTimer) + .setTimer(timer) .setAggregatedOpService(factoriesListener) .setIdProvider(ID_PROVIDER) .setConnectionTimeoutMillis(TIMEOUT) @@ -187,7 +183,6 @@ public class ConcurrentClientsTest { @AfterEach void afterEach() throws Exception { - hashedWheelTimer.stop(); server.shutdown().get(TIMEOUT, MILLISECONDS); serverBootstrapFactory.close(); if (clientFactory != null) { @@ -203,7 +198,7 @@ public class ConcurrentClientsTest { startServer(threads, serverCaps); clientFactory = clientClass == NetconfClientRunnable.class - ? new NetconfClientFactoryImpl(new SSHTransportStackFactory("client", threads)) : null; + ? new NetconfClientFactoryImpl(timer, new SSHTransportStackFactory("client", threads)) : null; final var futures = new ArrayList>(CONCURRENCY); for (int i = 0; i < CONCURRENCY; i++) { diff --git a/protocol/pom.xml b/protocol/pom.xml index 17726d5ae7..e4c6aa0349 100644 --- a/protocol/pom.xml +++ b/protocol/pom.xml @@ -31,6 +31,7 @@ netconf-api netconf-client + netconf-common netconf-server netconf-test-util restconf-api -- 2.36.6