X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fnetconf-testtool%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Ftest%2Ftool%2FNetconfDeviceSimulator.java;h=adcdea6073860b5f6b660faa356baf9cf7455df4;hp=4956c605fcfb8ba6e6429e0c4646f0bc939b955b;hb=1c6e2a5fad11f749ca174d7d0904f6be6292b2a7;hpb=0eba94d9411ea40945ddc8c732640c0cc004599f diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java index 4956c605fc..adcdea6073 100644 --- a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java @@ -19,13 +19,13 @@ import com.google.common.collect.Sets; import com.google.common.io.CharStreams; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.local.LocalAddress; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.HashedWheelTimer; import java.io.Closeable; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -34,6 +34,8 @@ import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.URI; import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.AbstractMap; import java.util.Date; import java.util.HashMap; @@ -42,8 +44,15 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.apache.sshd.common.util.ThreadUtils; +import org.apache.sshd.server.PasswordAuthenticator; +import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; +import org.apache.sshd.server.session.ServerSession; import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession; import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer; @@ -58,8 +67,9 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot; import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService; -import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; -import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator; +import org.opendaylight.controller.netconf.ssh.SshProxyServer; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfiguration; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; @@ -85,14 +95,22 @@ public class NetconfDeviceSimulator implements Closeable { private final NioEventLoopGroup nettyThreadgroup; private final HashedWheelTimer hashedWheelTimer; private final List devicesChannels = Lists.newArrayList(); + private final List sshWrappers = Lists.newArrayList(); + private final ScheduledExecutorService minaTimerExecutor; + private final ExecutorService nioExecutor; public NetconfDeviceSimulator() { - this(new NioEventLoopGroup(), new HashedWheelTimer()); + // TODO make pool size configurable + this(new NioEventLoopGroup(), new HashedWheelTimer(), + Executors.newScheduledThreadPool(8, new ThreadFactoryBuilder().setNameFormat("netconf-ssh-server-mina-timers-%d").build()), + ThreadUtils.newFixedThreadPool("netconf-ssh-server-nio-group", 8)); } - public NetconfDeviceSimulator(final NioEventLoopGroup eventExecutors, final HashedWheelTimer hashedWheelTimer) { + private NetconfDeviceSimulator(final NioEventLoopGroup eventExecutors, final HashedWheelTimer hashedWheelTimer, final ScheduledExecutorService minaTimerExecutor, final ExecutorService nioExecutor) { this.nettyThreadgroup = eventExecutors; this.hashedWheelTimer = hashedWheelTimer; + this.minaTimerExecutor = minaTimerExecutor; + this.nioExecutor = nioExecutor; } private NetconfServerDispatcher createDispatcher(final Map moduleBuilders, final boolean exi, final int generateConfigsTimeout) { @@ -162,17 +180,23 @@ public class NetconfDeviceSimulator implements Closeable { int currentPort = params.startingPort; final List openDevices = Lists.newArrayList(); + + // Generate key to temp folder + final PEMGeneratorHostKeyProvider keyPairProvider = getPemGeneratorHostKeyProvider(); + for (int i = 0; i < params.deviceCount; i++) { final InetSocketAddress address = getAddress(currentPort); final ChannelFuture server; if(params.ssh) { + final InetSocketAddress bindingAddress = InetSocketAddress.createUnresolved("0.0.0.0", currentPort); final LocalAddress tcpLocalAddress = new LocalAddress(address.toString()); server = dispatcher.createLocalServer(tcpLocalAddress); try { - final NetconfSSHServer sshServer = NetconfSSHServer.start(currentPort, tcpLocalAddress, nettyThreadgroup, getPemArray()); - sshServer.setAuthProvider(new AcceptingAuthProvider()); + final SshProxyServer sshServer = new SshProxyServer(minaTimerExecutor, nettyThreadgroup, nioExecutor); + sshServer.bind(getSshConfiguration(bindingAddress, tcpLocalAddress)); + sshWrappers.add(sshServer); } catch (final Exception e) { LOG.warn("Cannot start simulated device on {}, skipping", address, e); // Close local server and continue @@ -225,10 +249,27 @@ public class NetconfDeviceSimulator implements Closeable { return openDevices; } - private char[] getPemArray() { + private SshProxyServerConfiguration getSshConfiguration(final InetSocketAddress bindingAddress, final LocalAddress tcpLocalAddress) throws IOException { + return new SshProxyServerConfigurationBuilder() + .setBindingAddress(bindingAddress) + .setLocalAddress(tcpLocalAddress) + .setAuthenticator(new PasswordAuthenticator() { + @Override + public boolean authenticate(final String username, final String password, final ServerSession session) { + return true; + } + }) + .setKeyPairProvider(new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())) + .setIdleTimeout(Integer.MAX_VALUE) + .createSshProxyServerConfiguration(); + } + + private PEMGeneratorHostKeyProvider getPemGeneratorHostKeyProvider() { try { - return PEMGenerator.readOrGeneratePK(new File("PK")).toCharArray(); + final Path tempFile = Files.createTempFile("tempKeyNetconfTest", "suffix"); + return new PEMGeneratorHostKeyProvider(tempFile.toAbsolutePath().toString()); } catch (final IOException e) { + LOG.error("Unable to generate PEM key", e); throw new RuntimeException(e); } } @@ -263,15 +304,15 @@ public class NetconfDeviceSimulator implements Closeable { final Map> asts = Maps.newHashMap(); for (final SourceIdentifier loadedSource : loadedSources) { - try { - final CheckedFuture ast = consumer.getSchemaSource(loadedSource, ASTSchemaSource.class); - final CheckedFuture text = consumer.getSchemaSource(loadedSource, YangTextSchemaSource.class); - asts.put(loadedSource, new AbstractMap.SimpleEntry<>(ast.get(), text.get())); - } catch (final InterruptedException e) { - throw new RuntimeException(e); - } catch (final ExecutionException e) { - throw new RuntimeException("Cannot parse schema context", e); - } + try { + final CheckedFuture ast = consumer.getSchemaSource(loadedSource, ASTSchemaSource.class); + final CheckedFuture text = consumer.getSchemaSource(loadedSource, YangTextSchemaSource.class); + asts.put(loadedSource, new AbstractMap.SimpleEntry<>(ast.get(), text.get())); + } catch (final InterruptedException e) { + throw new RuntimeException(e); + } catch (final ExecutionException e) { + throw new RuntimeException("Cannot parse schema context", e); + } } return toModuleBuilders(asts); } @@ -317,10 +358,15 @@ public class NetconfDeviceSimulator implements Closeable { @Override public void close() { + for (final SshProxyServer sshWrapper : sshWrappers) { + sshWrapper.close(); + } for (final Channel deviceCh : devicesChannels) { deviceCh.close(); } nettyThreadgroup.shutdownGracefully(); + minaTimerExecutor.shutdownNow(); + nioExecutor.shutdownNow(); // close Everything } @@ -369,11 +415,11 @@ public class NetconfDeviceSimulator implements Closeable { static class SimulatedOperationService implements NetconfOperationService { private final Set capabilities; - private static SimulatedGet sGet; + private final long currentSessionId; public SimulatedOperationService(final Set capabilities, final long currentSessionId) { this.capabilities = capabilities; - sGet = new SimulatedGet(String.valueOf(currentSessionId)); + this.currentSessionId = currentSessionId; } @Override @@ -383,7 +429,12 @@ public class NetconfDeviceSimulator implements Closeable { @Override public Set getNetconfOperations() { - return Sets.newHashSet(sGet); + final DataList storage = new DataList(); + final SimulatedGet sGet = new SimulatedGet(String.valueOf(currentSessionId), storage); + final SimulatedEditConfig sEditConfig = new SimulatedEditConfig(String.valueOf(currentSessionId), storage); + final SimulatedGetConfig sGetConfig = new SimulatedGetConfig(String.valueOf(currentSessionId), storage); + final SimulatedCommit sCommit = new SimulatedCommit(String.valueOf(currentSessionId)); + return Sets.newHashSet(sGet, sGetConfig, sEditConfig, sCommit); } @Override