From: Juraj Veverka Date: Wed, 11 Oct 2017 11:27:58 +0000 (+0200) Subject: NetConf test tool improved so now it can be X-Git-Tag: release/oxygen~56^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=c41712817cb98e99fbe74744f6a3220be1db6d2e;p=netconf.git NetConf test tool improved so now it can be used as library not only as CLI tool. Change-Id: I14ca03d0b2cec0f6fe8b5994b3e195fa6de8a4d2 Signed-off-by: Juraj Veverka --- diff --git a/netconf/tools/netconf-testtool/README.adoc b/netconf/tools/netconf-testtool/README.adoc new file mode 100644 index 0000000000..cfdefdff9c --- /dev/null +++ b/netconf/tools/netconf-testtool/README.adoc @@ -0,0 +1,72 @@ +# NetConf TestTool + +This project is used to simulate NetConf devices in order to test NetConf +south-bound plugin and applications using this plugin. *netconf-testtool* +project is designed as versatile java library to be used for custom NetConf device +test simulations. + +## How to use as standalone application +* compile project +* start org.opendaylight.netconf.test.tool.Main + +## How to use it in your code +* Use maven dependency in your project +---- + + org.opendaylight.netconf + netconf-testtool-core + 0.1.0-SNAPSHOT + +---- +* Prepare configuration - models are loaded by classloader + from classpath. +---- +Set models = ImmutableSet.of( + "models/iana-afn-safi@2013-07-04.yang", + "models/ietf-inet-types@2013-07-15.yang", + "models/ietf-netconf@2011-06-01.yang", + "models/ietf-netconf-monitoring@2010-10-04.yang", + "models/ietf-netconf-monitoring-extension@2013-12-10.yang", + "models/ietf-yang-library@2016-06-21.yang", + "models/ietf-yang-types@2013-07-15.yang", + "models/nc-notifications@2008-07-14.yang", + "models/notifications@2008-07-14.yang", + ... +); +---- +* Prepare list of capabilities +---- +Set capabilities = ImmutableSet.of( + "urn:ietf:params:netconf:base:1.0", + "urn:ietf:params:netconf:base:1.1", + ... +); +---- +* Override RPC mapping provider org.opendaylight.netconf.test.tool.rpchandler.RpcHandler +---- +public class RpcHandlerImpl implements RpcHandler { + @Override + public Optional getResponse(XmlElement rpcElement) { + ... + return response; + } +} + +---- +* Start NetConf device simulator in your code +---- +public class Main { + + public static void main(String[] args) { + Configuration configuration = new ConfigurationBuilder() + .setModels(models) + .setCapabilities(capabilities) + .setRpcHandler(new RpcHandlerImpl()) + .build(); + NetConfDeviceSimulator netConfDeviceSimulator = + new NetConfDeviceSimulator(configuration); + netConfDeviceSimulator.start(); + } + +} +---- diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/Main.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/Main.java index 3a0b69a47e..4e6c2a327a 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/Main.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/Main.java @@ -37,6 +37,8 @@ import org.apache.karaf.features.internal.model.ConfigFile; import org.apache.karaf.features.internal.model.Feature; import org.apache.karaf.features.internal.model.Features; import org.apache.karaf.features.internal.model.JaxbUtil; +import org.opendaylight.netconf.test.tool.config.Configuration; +import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,10 +54,11 @@ public final class Main { .getLogger(Logger.ROOT_LOGGER_NAME); root.setLevel(params.debug ? Level.DEBUG : Level.INFO); - final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator(params.threadPoolSize); + final Configuration configuration = new ConfigurationBuilder().from(params).build(); + final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator(configuration); try { LOG.debug("Trying to start netconf test-tool with parameters {}", params); - final List openDevices = netconfDeviceSimulator.start(params); + final List openDevices = netconfDeviceSimulator.start(); if (openDevices.size() == 0) { LOG.error("Failed to start any simulated devices, exiting..."); System.exit(1); 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 53ca53ab70..dffd79e6c5 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 @@ -42,7 +42,6 @@ import org.opendaylight.controller.config.util.capability.BasicCapability; import org.opendaylight.controller.config.util.capability.Capability; import org.opendaylight.controller.config.util.capability.YangModuleCapability; import org.opendaylight.netconf.api.monitoring.NetconfMonitoringService; -import org.opendaylight.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.netconf.impl.NetconfServerDispatcherImpl; import org.opendaylight.netconf.impl.NetconfServerSessionNegotiatorFactory; import org.opendaylight.netconf.impl.SessionIdProvider; @@ -53,7 +52,11 @@ import org.opendaylight.netconf.monitoring.osgi.NetconfMonitoringOperationServic import org.opendaylight.netconf.ssh.SshProxyServer; import org.opendaylight.netconf.ssh.SshProxyServerConfiguration; import org.opendaylight.netconf.ssh.SshProxyServerConfigurationBuilder; +import org.opendaylight.netconf.test.tool.config.Configuration; import org.opendaylight.netconf.test.tool.customrpc.SettableOperationProvider; +import org.opendaylight.netconf.test.tool.operations.OperationsProvider; +import org.opendaylight.netconf.test.tool.rpchandler.SettableOperationRpcProvider; +import org.opendaylight.netconf.test.tool.schemacache.SchemaSourceCache; import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -83,27 +86,23 @@ public class NetconfDeviceSimulator implements Closeable { private final List sshWrappers = Lists.newArrayList(); private final ScheduledExecutorService minaTimerExecutor; private final ExecutorService nioExecutor; + private final Configuration configuration; private SchemaContext schemaContext; private boolean sendFakeSchema = false; - public NetconfDeviceSimulator(final int threadPoolSize) { - this(new NioEventLoopGroup(), new HashedWheelTimer(), - Executors.newScheduledThreadPool(threadPoolSize, - new ThreadFactoryBuilder().setNameFormat("netconf-ssh-server-mina-timers-%d").build()), - ThreadUtils.newFixedThreadPool("netconf-ssh-server-nio-group", threadPoolSize)); - } - - 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; + public NetconfDeviceSimulator(Configuration configuration) { + this.configuration = configuration; + this.nettyThreadgroup = new NioEventLoopGroup(); + this.hashedWheelTimer = new HashedWheelTimer(); + this.minaTimerExecutor = Executors.newScheduledThreadPool(configuration.getThreadPoolSize(), + new ThreadFactoryBuilder().setNameFormat("netconf-ssh-server-mina-timers-%d").build()); + this.nioExecutor = ThreadUtils + .newFixedThreadPool("netconf-ssh-server-nio-group", configuration.getThreadPoolSize()); } private NetconfServerDispatcherImpl createDispatcher(final Set capabilities, - final SchemaSourceProvider sourceProvider, final TesttoolParameters params) { + final SchemaSourceProvider sourceProvider) { final Set transformedCapabilities = Sets.newHashSet(Collections2.transform(capabilities, input -> { if (sendFakeSchema) { @@ -118,15 +117,13 @@ public class NetconfDeviceSimulator implements Closeable { final SessionIdProvider idProvider = new SessionIdProvider(); final NetconfOperationServiceFactory aggregatedNetconfOperationServiceFactory = createOperationServiceFactory( - sourceProvider, params, transformedCapabilities, monitoringService1, idProvider); + sourceProvider, transformedCapabilities, monitoringService1, idProvider); - final Set serverCapabilities = params.exi - ? NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES - : Sets.newHashSet(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0, - XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1); + final Set serverCapabilities = configuration.getCapabilities(); final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new TesttoolNegotiationFactory( - hashedWheelTimer, aggregatedNetconfOperationServiceFactory, idProvider, params.generateConfigsTimeout, + hashedWheelTimer, aggregatedNetconfOperationServiceFactory, idProvider, + configuration.getGenerateConfigsTimeout(), monitoringService1, serverCapabilities); final NetconfServerDispatcherImpl.ServerChannelInitializer serverChannelInitializer = @@ -135,20 +132,25 @@ public class NetconfDeviceSimulator implements Closeable { } private NetconfOperationServiceFactory createOperationServiceFactory( - final SchemaSourceProvider sourceProvider, final TesttoolParameters params, + final SchemaSourceProvider sourceProvider, final Set transformedCapabilities, final NetconfMonitoringService monitoringService1, final SessionIdProvider idProvider) { final AggregatedNetconfOperationServiceFactory aggregatedNetconfOperationServiceFactory = new AggregatedNetconfOperationServiceFactory(); final NetconfOperationServiceFactory operationProvider; - if (params.mdSal) { + if (configuration.isMdSal()) { + LOG.info("using MdsalOperationProvider."); operationProvider = new MdsalOperationProvider( idProvider, transformedCapabilities, schemaContext, sourceProvider); - } else { + } else if (configuration.isXmlConfigurationProvided()) { + LOG.info("using SimulatedOperationProvider."); operationProvider = new SimulatedOperationProvider(idProvider, transformedCapabilities, - Optional.fromNullable(params.notificationFile), - Optional.fromNullable(params.initialConfigXMLFile)); + Optional.fromNullable(configuration.getNotificationFile()), + Optional.fromNullable(configuration.getInitialConfigXMLFile())); + } else { + LOG.info("using OperationsProvider."); + operationProvider = new OperationsProvider(idProvider, transformedCapabilities); } @@ -157,39 +159,44 @@ public class NetconfDeviceSimulator implements Closeable { new NetconfMonitoringOperationService(monitoringService1)); aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(operationProvider); aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(monitoringService); - if (params.rpcConfig != null) { - final SettableOperationProvider settableService = new SettableOperationProvider(params.rpcConfig); + if (configuration.getRpcConfigFile() != null) { + final SettableOperationProvider settableService = + new SettableOperationProvider(configuration.getRpcConfigFile()); + aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(settableService); + } else { + final SettableOperationRpcProvider settableService = + new SettableOperationRpcProvider(configuration.getRpcHandler()); aggregatedNetconfOperationServiceFactory.onAddNetconfOperationServiceFactory(settableService); } return aggregatedNetconfOperationServiceFactory; } - public List start(final TesttoolParameters params) { + public List start() { LOG.info("Starting {}, {} simulated devices starting on port {}", - params.deviceCount, params.ssh ? "SSH" : "TCP", params.startingPort); + configuration.getDeviceCount(), configuration.isSsh() ? "SSH" : "TCP", configuration.getStartingPort()); final SharedSchemaRepository schemaRepo = new SharedSchemaRepository("netconf-simulator"); - final Set capabilities = parseSchemasToModuleCapabilities(params, schemaRepo); + final Set capabilities = parseSchemasToModuleCapabilities(schemaRepo); final NetconfServerDispatcherImpl dispatcher = createDispatcher(capabilities, - sourceIdentifier -> schemaRepo.getSchemaSource(sourceIdentifier, YangTextSchemaSource.class), params); + sourceIdentifier -> schemaRepo.getSchemaSource(sourceIdentifier, YangTextSchemaSource.class)); - int currentPort = params.startingPort; + int currentPort = configuration.getStartingPort(); final List openDevices = Lists.newArrayList(); // Generate key to temp folder final PEMGeneratorHostKeyProvider keyPairProvider = getPemGeneratorHostKeyProvider(); - for (int i = 0; i < params.deviceCount; i++) { + for (int i = 0; i < configuration.getDeviceCount(); i++) { if (currentPort > 65535) { LOG.warn("Port cannot be greater than 65535, stopping further attempts."); break; } - final InetSocketAddress address = getAddress(params.ip, currentPort); + final InetSocketAddress address = getAddress(configuration.getIp(), currentPort); final ChannelFuture server; - if (params.ssh) { + if (configuration.isSsh()) { final InetSocketAddress bindingAddress = InetSocketAddress.createUnresolved("0.0.0.0", currentPort); final LocalAddress tcpLocalAddress = new LocalAddress(address.toString()); @@ -245,9 +252,9 @@ public class NetconfDeviceSimulator implements Closeable { openDevices.add(currentPort - 1); } - if (openDevices.size() == params.deviceCount) { + if (openDevices.size() == configuration.getDeviceCount()) { LOG.info("All simulated devices started successfully from port {} to {}", - params.startingPort, currentPort - 1); + configuration.getStartingPort(), currentPort - 1); } else if (openDevices.size() == 0) { LOG.warn("No simulated devices started."); } else { @@ -278,12 +285,9 @@ public class NetconfDeviceSimulator implements Closeable { } } - private Set parseSchemasToModuleCapabilities(final TesttoolParameters params, - final SharedSchemaRepository consumer) { + private Set parseSchemasToModuleCapabilities(final SharedSchemaRepository consumer) { final Set loadedSources = Sets.newHashSet(); - consumer.registerSchemaSourceListener(TextToASTTransformer.create(consumer, consumer)); - consumer.registerSchemaSourceListener(new SchemaSourceListener() { @Override public void schemaSourceEncountered(final SchemaSourceRepresentation schemaSourceRepresentation) {} @@ -299,10 +303,18 @@ public class NetconfDeviceSimulator implements Closeable { public void schemaSourceUnregistered(final PotentialSchemaSource potentialSchemaSource) {} }); - if (params.schemasDir != null) { + if (configuration.getSchemasDir() != null) { + LOG.info("Loading models from directory."); final FilesystemSchemaSourceCache cache = new FilesystemSchemaSourceCache<>( - consumer, YangTextSchemaSource.class, params.schemasDir); + consumer, YangTextSchemaSource.class, configuration.getSchemasDir()); + consumer.registerSchemaSourceListener(cache); + } else if (configuration.getModels() != null) { + LOG.info("Loading models from classpath."); + final SchemaSourceCache cache = new SchemaSourceCache<>( + consumer, YangTextSchemaSource.class, configuration.getModels()); consumer.registerSchemaSourceListener(cache); + } else { + LOG.info("Custom module loading skipped."); } addDefaultSchemas(consumer); @@ -399,6 +411,6 @@ public class NetconfDeviceSimulator implements Closeable { nettyThreadgroup.shutdownGracefully(); minaTimerExecutor.shutdownNow(); nioExecutor.shutdownNow(); - // close Everything } + } diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/ScaleUtil.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/ScaleUtil.java index e28d936f6d..36e336ad69 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/ScaleUtil.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/ScaleUtil.java @@ -32,6 +32,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import net.sourceforge.argparse4j.inf.ArgumentParser; import net.sourceforge.argparse4j.inf.ArgumentParserException; +import org.opendaylight.netconf.test.tool.config.Configuration; +import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,9 +62,10 @@ public class ScaleUtil { while (true) { root.warn("Starting scale test with {} devices", params.deviceCount); final ScheduledFuture timeoutGuardFuture = EXECUTOR.schedule(new TimeoutGuard(), TIMEOUT, TimeUnit.MINUTES); - final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator(params.threadAmount); + final Configuration configuration = new ConfigurationBuilder().from(params).build(); + final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator(configuration); try { - final List openDevices = netconfDeviceSimulator.start(params); + final List openDevices = netconfDeviceSimulator.start(); if (openDevices.size() == 0) { root.error("Failed to start any simulated devices, exiting..."); System.exit(1); diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TestToolUtils.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TestToolUtils.java index b2c6ca0c31..15fd535de8 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TestToolUtils.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TestToolUtils.java @@ -8,19 +8,23 @@ package org.opendaylight.netconf.test.tool; -public class TestToolUtils { +import java.io.InputStream; + +public final class TestToolUtils { public static String getMac(long mac) { final StringBuilder builder = new StringBuilder(Long.toString(mac, 16)); - for (int i = builder.length(); i < 12; i++) { builder.insert(0, "0"); } - for (int j = builder.length() - 2; j >= 2; j -= 2) { builder.insert(j, ":"); } - return builder.toString(); } + + public static InputStream getDataAsStream(final String path) { + return TestToolUtils.class.getClassLoader().getResourceAsStream(path); + } + } diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolParameters.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolParameters.java index ecd9c1b5a6..775aa7670b 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolParameters.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolParameters.java @@ -90,10 +90,8 @@ public class TesttoolParameters { @Arg(dest = "time-out") public long timeOut; private InputStream stream; - @Arg(dest = "ip") public String ip; - @Arg(dest = "thread-pool-size") public int threadPoolSize; @Arg(dest = "rpc-config") diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/config/Configuration.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/config/Configuration.java new file mode 100644 index 0000000000..c57f158174 --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/config/Configuration.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. 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.test.tool.config; + +import com.google.common.collect.ImmutableSet; +import java.io.File; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import org.opendaylight.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.netconf.test.tool.rpchandler.RpcHandler; +import org.opendaylight.netconf.test.tool.rpchandler.RpcHandlerDefault; + + +public class Configuration { + + public static final Set DEFAULT_BASE_CAPABILITIES_EXI = ImmutableSet.of( + XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0, + XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1, + XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_EXI_1_0 + ); + + public static final Set DEFAULT_BASE_CAPABILITIES = ImmutableSet.of( + XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0, + XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1 + ); + + private int generateConfigsTimeout = (int) TimeUnit.MINUTES.toMillis(30); + private int threadPoolSize = 8; + private int startingPort = 17830; + private int deviceCount = 1; + private boolean ssh = true; + private String ip = "0.0.0.0"; + + private Set models; + private Set capabilities = DEFAULT_BASE_CAPABILITIES_EXI; + private RpcHandler rpcHandler = new RpcHandlerDefault(); + + @Deprecated + private boolean mdSal = false; + + @Deprecated + private File rpcConfigFile; + + @Deprecated + private File notificationFile; + + @Deprecated + private File initialConfigXMLFile; + + @Deprecated + private File schemasDir; + + public Configuration() { + } + + public int getThreadPoolSize() { + return threadPoolSize; + } + + public void setThreadPoolSize(int threadPoolSize) { + this.threadPoolSize = threadPoolSize; + } + + public int getStartingPort() { + return startingPort; + } + + public void setStartingPort(int startingPort) { + this.startingPort = startingPort; + } + + public int getDeviceCount() { + return deviceCount; + } + + public void setDeviceCount(int deviceCount) { + this.deviceCount = deviceCount; + } + + public int getGenerateConfigsTimeout() { + return generateConfigsTimeout; + } + + public void setGenerateConfigsTimeout(int generateConfigsTimeout) { + this.generateConfigsTimeout = generateConfigsTimeout; + } + + public boolean isSsh() { + return ssh; + } + + public void setSsh(boolean ssh) { + this.ssh = ssh; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public Set getModels() { + return models; + } + + public void setModels(Set models) { + this.models = models; + } + + public Set getCapabilities() { + return capabilities; + } + + public void setCapabilities(Set capabilities) { + this.capabilities = capabilities; + } + + public RpcHandler getRpcHandler() { + return rpcHandler; + } + + public void setRpcHandler(RpcHandler rpcHandler) { + this.rpcHandler = rpcHandler; + } + + @Deprecated + public boolean isMdSal() { + return mdSal; + } + + @Deprecated + public void setMdSal(boolean mdSal) { + this.mdSal = mdSal; + } + + @Deprecated + public File getRpcConfigFile() { + return rpcConfigFile; + } + + @Deprecated + public void setRpcConfigFile(File rpcConfigFile) { + this.rpcConfigFile = rpcConfigFile; + } + + @Deprecated + public File getNotificationFile() { + return notificationFile; + } + + @Deprecated + public void setNotificationFile(File notificationFile) { + this.notificationFile = notificationFile; + } + + @Deprecated + public File getInitialConfigXMLFile() { + return initialConfigXMLFile; + } + + @Deprecated + public void setInitialConfigXMLFile(File initialConfigXMLFile) { + this.initialConfigXMLFile = initialConfigXMLFile; + } + + @Deprecated + public boolean isXmlConfigurationProvided() { + return initialConfigXMLFile != null && notificationFile != null; + } + + @Deprecated + public File getSchemasDir() { + return schemasDir; + } + + @Deprecated + public void setSchemasDir(File schemasDir) { + this.schemasDir = schemasDir; + } + +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/config/ConfigurationBuilder.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/config/ConfigurationBuilder.java new file mode 100644 index 0000000000..2ed4aa247a --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/config/ConfigurationBuilder.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. 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.test.tool.config; + +import java.io.File; +import java.util.Set; +import org.opendaylight.netconf.test.tool.TesttoolParameters; +import org.opendaylight.netconf.test.tool.rpchandler.RpcHandler; + +public class ConfigurationBuilder { + + private Configuration configuration; + + public ConfigurationBuilder() { + this.configuration = new Configuration(); + } + + public ConfigurationBuilder setThreadPoolSize(int threadPoolSize) { + this.configuration.setThreadPoolSize(threadPoolSize); + return this; + } + + public ConfigurationBuilder setGenerateConfigsTimeout(int generateConfigsTimeout) { + this.configuration.setGenerateConfigsTimeout(generateConfigsTimeout); + return this; + } + + public ConfigurationBuilder setModels(Set models) { + this.configuration.setModels(models); + return this; + } + + public ConfigurationBuilder setCapabilities(Set capabilities) { + this.configuration.setCapabilities(capabilities); + return this; + } + + public ConfigurationBuilder setStartingPort(int startingPort) { + this.configuration.setStartingPort(startingPort); + return this; + } + + public ConfigurationBuilder setDeviceCount(int deviceCount) { + this.configuration.setDeviceCount(deviceCount); + return this; + } + + public ConfigurationBuilder setSsh(boolean ssh) { + this.configuration.setSsh(ssh); + return this; + } + + public ConfigurationBuilder setIp(String ip) { + this.configuration.setIp(ip); + return this; + } + + public ConfigurationBuilder setRpcMapping(RpcHandler rpcHandler) { + this.configuration.setRpcHandler(rpcHandler); + return this; + } + + @Deprecated + public ConfigurationBuilder setMdSal(boolean mdSal) { + this.configuration.setMdSal(mdSal); + return this; + } + + @Deprecated + public ConfigurationBuilder setRpcConfigFile(File rpcConfigFile) { + this.configuration.setRpcConfigFile(rpcConfigFile); + return this; + } + + @Deprecated + public ConfigurationBuilder setInitialConfigXMLFile(File initialConfigXMLFile) { + this.configuration.setInitialConfigXMLFile(initialConfigXMLFile); + return this; + } + + @Deprecated + public ConfigurationBuilder setNotificationFile(File notificationFile) { + this.configuration.setNotificationFile(notificationFile); + return this; + } + + public ConfigurationBuilder from(Configuration configuration) { + this.configuration.setThreadPoolSize(configuration.getThreadPoolSize()); + this.configuration.setGenerateConfigsTimeout(configuration.getGenerateConfigsTimeout()); + this.configuration.setModels(configuration.getModels()); + this.configuration.setCapabilities(configuration.getCapabilities()); + this.configuration.setStartingPort(configuration.getStartingPort()); + this.configuration.setDeviceCount(configuration.getDeviceCount()); + this.configuration.setSsh(configuration.isSsh()); + this.configuration.setIp(configuration.getIp()); + this.configuration.setRpcHandler(configuration.getRpcHandler()); + this.configuration.setMdSal(configuration.isMdSal()); + this.configuration.setRpcConfigFile(configuration.getRpcConfigFile()); + this.configuration.setInitialConfigXMLFile(configuration.getInitialConfigXMLFile()); + this.configuration.setNotificationFile(configuration.getNotificationFile()); + this.configuration.setSchemasDir(configuration.getSchemasDir()); + return this; + } + + public ConfigurationBuilder from(TesttoolParameters testtoolParameters) { + this.configuration.setGenerateConfigsTimeout(testtoolParameters.generateConfigsTimeout); + this.configuration.setStartingPort(testtoolParameters.startingPort); + this.configuration.setDeviceCount(testtoolParameters.deviceCount); + this.configuration.setSsh(testtoolParameters.ssh); + this.configuration.setIp(testtoolParameters.ip); + this.configuration.setMdSal(testtoolParameters.mdSal); + this.configuration.setRpcConfigFile(testtoolParameters.rpcConfig); + this.configuration.setInitialConfigXMLFile(testtoolParameters.initialConfigXMLFile); + this.configuration.setNotificationFile(testtoolParameters.notificationFile); + this.configuration.setSchemasDir(testtoolParameters.schemasDir); + return this; + } + + public Configuration build() { + return configuration; + } + +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/operations/OperationsProvider.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/operations/OperationsProvider.java new file mode 100644 index 0000000000..de05df7996 --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/operations/OperationsProvider.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. 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.test.tool.operations; + +import com.google.common.base.Optional; +import com.google.common.collect.Sets; +import java.util.Collections; +import java.util.Set; +import org.opendaylight.controller.config.util.capability.Capability; +import org.opendaylight.netconf.api.monitoring.CapabilityListener; +import org.opendaylight.netconf.impl.SessionIdProvider; +import org.opendaylight.netconf.mapping.api.NetconfOperation; +import org.opendaylight.netconf.mapping.api.NetconfOperationService; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; +import org.opendaylight.netconf.test.tool.rpc.DataList; +import org.opendaylight.netconf.test.tool.rpc.SimulatedCommit; +import org.opendaylight.netconf.test.tool.rpc.SimulatedCreateSubscription; +import org.opendaylight.netconf.test.tool.rpc.SimulatedDiscardChanges; +import org.opendaylight.netconf.test.tool.rpc.SimulatedEditConfig; +import org.opendaylight.netconf.test.tool.rpc.SimulatedGet; +import org.opendaylight.netconf.test.tool.rpc.SimulatedGetConfig; +import org.opendaylight.netconf.test.tool.rpc.SimulatedLock; +import org.opendaylight.netconf.test.tool.rpc.SimulatedUnLock; + + +public class OperationsProvider implements NetconfOperationServiceFactory { + private final Set caps; + private final SimulatedOperationService simulatedOperationService; + + public OperationsProvider(final SessionIdProvider idProvider, + final Set caps) { + this.caps = caps; + simulatedOperationService = new SimulatedOperationService( + idProvider.getCurrentSessionId()); + } + + @Override + public Set getCapabilities() { + return caps; + } + + @Override + public AutoCloseable registerCapabilityListener( + final CapabilityListener listener) { + listener.onCapabilitiesChanged(caps, Collections.emptySet()); + return new AutoCloseable() { + @Override + public void close() throws Exception { + } + }; + } + + @Override + public NetconfOperationService createService( + final String netconfSessionIdForReporting) { + return simulatedOperationService; + } + + static class SimulatedOperationService implements NetconfOperationService { + private final long currentSessionId; + + SimulatedOperationService(final long currentSessionId) { + this.currentSessionId = currentSessionId; + } + + @Override + public Set getNetconfOperations() { + 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, Optional.absent()); + final SimulatedCommit sCommit = new SimulatedCommit(String.valueOf(currentSessionId)); + final SimulatedLock sLock = new SimulatedLock(String.valueOf(currentSessionId)); + final SimulatedUnLock sUnlock = new SimulatedUnLock(String.valueOf(currentSessionId)); + final SimulatedCreateSubscription sCreateSubs = new SimulatedCreateSubscription( + String.valueOf(currentSessionId), Optional.absent()); + final SimulatedDiscardChanges sDiscardChanges = new SimulatedDiscardChanges( + String.valueOf(currentSessionId)); + return Sets.newHashSet( + sGet, sGetConfig, sEditConfig, sCommit, sLock, sUnlock, sCreateSubs, sDiscardChanges); + } + + @Override + public void close() { + } + + } +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/RpcHandler.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/RpcHandler.java new file mode 100644 index 0000000000..ec0105b779 --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/RpcHandler.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. 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.test.tool.rpchandler; + +import java.util.Optional; +import org.opendaylight.controller.config.util.xml.XmlElement; +import org.w3c.dom.Document; + +public interface RpcHandler { + + Optional getResponse(XmlElement rpcElement); + +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/RpcHandlerDefault.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/RpcHandlerDefault.java new file mode 100644 index 0000000000..5a84ea6acb --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/RpcHandlerDefault.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. 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.test.tool.rpchandler; + +import java.util.Optional; +import org.opendaylight.controller.config.util.xml.XmlElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +public class RpcHandlerDefault implements RpcHandler { + + private static final Logger LOG = LoggerFactory.getLogger(RpcHandlerDefault.class); + + @Override + public Optional getResponse(XmlElement rpcElement) { + LOG.info("getResponse: {}", rpcElement.toString()); + return null; + } + +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/SettableOperationRpcProvider.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/SettableOperationRpcProvider.java new file mode 100644 index 0000000000..66199d984c --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/SettableOperationRpcProvider.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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.test.tool.rpchandler; + +import java.util.Collections; +import java.util.Set; +import org.opendaylight.controller.config.util.capability.Capability; +import org.opendaylight.netconf.api.monitoring.CapabilityListener; +import org.opendaylight.netconf.mapping.api.NetconfOperation; +import org.opendaylight.netconf.mapping.api.NetconfOperationService; +import org.opendaylight.netconf.mapping.api.NetconfOperationServiceFactory; + +public class SettableOperationRpcProvider implements NetconfOperationServiceFactory { + + private final RpcHandler rpcHandler; + + public SettableOperationRpcProvider(RpcHandler rpcHandler) { + this.rpcHandler = rpcHandler; + } + + @Override + public Set getCapabilities() { + return Collections.emptySet(); + } + + @Override + public AutoCloseable registerCapabilityListener(final CapabilityListener listener) { + return () -> { + //no op + }; + } + + @Override + public NetconfOperationService createService(final String netconfSessionIdForReporting) { + return new SettableOperationService(rpcHandler); + } + + private static class SettableOperationService implements NetconfOperationService { + + private final SettableRpc rpc; + + private SettableOperationService(RpcHandler rpcHandler) { + this.rpc = new SettableRpc(rpcHandler); + } + + @Override + public Set getNetconfOperations() { + return Collections.singleton(rpc); + } + + @Override + public void close() { + // no op + } + } +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/SettableRpc.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/SettableRpc.java new file mode 100644 index 0000000000..1f2b97df62 --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/rpchandler/SettableRpc.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 Cisco Systems, Inc. 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.test.tool.rpchandler; + +import java.util.Optional; +import org.opendaylight.controller.config.util.xml.DocumentedException; +import org.opendaylight.controller.config.util.xml.XmlElement; +import org.opendaylight.controller.config.util.xml.XmlUtil; +import org.opendaylight.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.netconf.mapping.api.HandlingPriority; +import org.opendaylight.netconf.mapping.api.NetconfOperation; +import org.opendaylight.netconf.mapping.api.NetconfOperationChainedExecution; +import org.w3c.dom.Document; + +/** + * {@link NetconfOperation} implementation. It can be configured to intercept rpcs with defined input + * and reply with defined output. If input isn't defined, rpc handling is delegated to the subsequent + * {@link NetconfOperation} which is able to handle it. + */ +class SettableRpc implements NetconfOperation { + + private final RpcHandler rpcHandler; + + SettableRpc(RpcHandler rpcHandler) { + this.rpcHandler = rpcHandler; + } + + @Override + public HandlingPriority canHandle(final Document message) throws DocumentedException { + return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY.increasePriority(1000); + } + + @Override + public Document handle(final Document requestMessage, final NetconfOperationChainedExecution subsequentOperation) + throws DocumentedException { + final XmlElement requestElement = XmlElement.fromDomDocument(requestMessage); + final XmlElement rpcElement = requestElement.getOnlyChildElement(); + final String msgId = requestElement.getAttribute(XmlNetconfConstants.MESSAGE_ID); + final Optional response = rpcHandler.getResponse(rpcElement); + if (response.isPresent()) { + final Document document = response.get(); + checkForError(document); + document.getDocumentElement().setAttribute(XmlNetconfConstants.MESSAGE_ID, msgId); + return document; + } else if (subsequentOperation.isExecutionTermination()) { + throw new DocumentedException("Mapping not found " + XmlUtil.toString(requestMessage), + DocumentedException.ErrorType.APPLICATION, DocumentedException.ErrorTag.OPERATION_NOT_SUPPORTED, + DocumentedException.ErrorSeverity.ERROR); + } else { + return subsequentOperation.execute(requestMessage); + } + } + + private void checkForError(final Document document) throws DocumentedException { + final XmlElement rpcReply = XmlElement.fromDomDocument(document); + if (rpcReply.getOnlyChildElementOptionally("rpc-error").isPresent()) { + throw DocumentedException.fromXMLDocument(document); + } + } + +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/schemacache/ModelData.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/schemacache/ModelData.java new file mode 100644 index 0000000000..ae431dc803 --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/schemacache/ModelData.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. 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.test.tool.schemacache; + +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; + +public class ModelData { + + private SourceIdentifier id; + private String path; + + public ModelData(SourceIdentifier id, String path) { + this.id = id; + this.path = path; + } + + public SourceIdentifier getId() { + return id; + } + + public String getPath() { + return path; + } +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/schemacache/SchemaSourceCache.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/schemacache/SchemaSourceCache.java new file mode 100644 index 0000000000..9ece5a910b --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/schemacache/SchemaSourceCache.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. 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.test.tool.schemacache; + +import com.google.common.base.MoreObjects.ToStringHelper; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.opendaylight.netconf.test.tool.TestToolUtils; +import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException; +import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource.Costs; +import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry; +import org.opendaylight.yangtools.yang.model.repo.util.AbstractSchemaSourceCache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Cache implementation that stores schemas in form of files under provided folder. + */ +public final class SchemaSourceCache + extends AbstractSchemaSourceCache { + + private static final Logger LOG = LoggerFactory.getLogger(SchemaSourceCache.class); + + public static final Pattern CACHED_FILE_PATTERN = + Pattern.compile( + ".*/(?[^@]+)" + "(@(?" + SourceIdentifier.REVISION_PATTERN + "))?.yang"); + + private final Class representation; + private final Set modelList; + private Map cachedSchemas; + + public SchemaSourceCache( + final SchemaSourceRegistry consumer, final Class representation, final Set modelList) { + super(consumer, representation, Costs.LOCAL_IO); + this.representation = representation; + this.modelList = Preconditions.checkNotNull(modelList); + init(); + } + + /** + * Restore cache state. + */ + private void init() { + cachedSchemas = new HashMap<>(); + for (String modelPath: modelList) { + Optional sourceIdentifierOptional = getSourceIdentifier(modelPath); + if (sourceIdentifierOptional.isPresent()) { + SourceIdentifier sourceIdentifier = sourceIdentifierOptional.get(); + cachedSchemas.put(sourceIdentifier.toYangFilename(), new ModelData(sourceIdentifier, modelPath)); + } else { + LOG.debug("Skipping caching model {}, cannot restore source identifier from model path," + + " does not match {}", modelPath, CACHED_FILE_PATTERN); + } + } + for (final ModelData cachedSchema : cachedSchemas.values()) { + register(cachedSchema.getId()); + } + } + + @Override + public synchronized CheckedFuture getSource( + final SourceIdentifier sourceIdentifier) { + ModelData modelData = cachedSchemas.get(sourceIdentifier.toYangFilename()); + if (modelData != null) { + final SchemaSourceRepresentation restored = restoreAsType(modelData.getId(), modelData.getPath()); + return Futures.immediateCheckedFuture(representation.cast(restored)); + } else { + LOG.debug("Source {} not found in cache as {}", sourceIdentifier); + return Futures.immediateFailedCheckedFuture(new MissingSchemaSourceException("Source not found", + sourceIdentifier)); + } + } + + @Override + protected synchronized void offer(final T source) { + LOG.trace("Source {} offered to cache", source.getIdentifier()); + } + + private YangTextSchemaSource restoreAsType(final SourceIdentifier sourceIdentifier, final String cachedSource) { + return new YangTextSchemaSource(sourceIdentifier) { + + @Override + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return toStringHelper; + } + + @Override + public InputStream openStream() throws IOException { + return TestToolUtils.getDataAsStream(cachedSource); + } + }; + } + + private static Optional getSourceIdentifier(final String fileName) { + final Matcher matcher = CACHED_FILE_PATTERN.matcher(fileName); + if (matcher.matches()) { + final String moduleName = matcher.group("moduleName"); + final String revision = matcher.group("revision"); + return Optional.of(RevisionSourceIdentifier.create(moduleName, Optional.fromNullable(revision))); + } + return Optional.absent(); + } + +}