2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.netconf.test.tool;
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static com.google.common.base.Preconditions.checkNotNull;
13 import static com.google.common.base.Preconditions.checkState;
15 import com.google.common.io.Files;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InputStreamReader;
20 import java.util.List;
22 import java.util.concurrent.TimeUnit;
23 import net.sourceforge.argparse4j.ArgumentParsers;
24 import net.sourceforge.argparse4j.annotation.Arg;
25 import net.sourceforge.argparse4j.inf.ArgumentParser;
26 import net.sourceforge.argparse4j.inf.ArgumentParserException;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
31 import com.google.common.base.Charsets;
32 import com.google.common.io.CharStreams;
34 public final class Main {
36 // TODO add logback config
38 // TODO make exi configurable
40 private static final Logger LOG = LoggerFactory.getLogger(Main.class);
44 @Arg(dest = "schemas-dir")
45 public File schemasDir;
47 @Arg(dest = "devices-count")
48 public int deviceCount;
50 @Arg(dest = "starting-port")
51 public int startingPort;
53 @Arg(dest = "generate-config-connection-timeout")
54 public int generateConfigsTimeout;
56 @Arg(dest = "generate-config-address")
57 public String generateConfigsAddress;
59 @Arg(dest = "generate-configs-dir")
60 public File generateConfigsDir;
62 @Arg(dest = "generate-configs-batch-size")
63 public int generateConfigBatchSize;
71 static ArgumentParser getParser() {
72 final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool");
73 parser.addArgument("--devices-count")
77 .help("Number of simulated netconf devices to spin")
78 .dest("devices-count");
80 parser.addArgument("--schemas-dir")
83 .help("Directory containing yang schemas to describe simulated devices")
86 parser.addArgument("--starting-port")
89 .help("First port for simulated device. Each other device will have previous+1 port number")
90 .dest("starting-port");
92 parser.addArgument("--generate-config-connection-timeout")
94 .setDefault((int)TimeUnit.MINUTES.toMillis(5))
95 .help("Timeout to be generated in initial config files")
96 .dest("generate-config-connection-timeout");
98 parser.addArgument("--generate-config-address")
100 .setDefault("127.0.0.1")
101 .help("Address to be placed in generated configs")
102 .dest("generate-config-address");
104 parser.addArgument("--generate-configs-batch-size")
107 .help("Number of connector configs per generated file")
108 .dest("generate-configs-batch-size");
110 parser.addArgument("--generate-configs-dir")
112 .help("Directory where initial config files for ODL distribution should be generated")
113 .dest("generate-configs-dir");
115 parser.addArgument("--ssh")
118 .help("Whether to use ssh for transport or just pure tcp")
121 parser.addArgument("--exi")
124 .help("Whether to use exi to transport xml content")
131 checkArgument(deviceCount > 0, "Device count has to be > 0");
132 checkArgument(startingPort > 1024, "Starting port has to be > 1024");
134 checkArgument(schemasDir.exists(), "Schemas dir has to exist");
135 checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory");
136 checkArgument(schemasDir.canRead(), "Schemas dir has to be readable");
140 public static void main(final String[] args) {
141 ch.ethz.ssh2.log.Logger.enabled = true;
143 final Params params = parseArgs(args, Params.getParser());
146 final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator();
148 final List<Integer> openDevices = netconfDeviceSimulator.start(params);
149 if(params.generateConfigsDir != null) {
150 new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout, params.generateConfigsAddress);
152 } catch (final Exception e) {
153 LOG.error("Unhandled exception", e);
154 netconfDeviceSimulator.close();
159 synchronized (netconfDeviceSimulator) {
161 netconfDeviceSimulator.wait();
162 } catch (final InterruptedException e) {
163 throw new RuntimeException(e);
169 private static Params parseArgs(final String[] args, final ArgumentParser parser) {
170 final Params opt = new Params();
172 parser.parseArgs(args, opt);
174 } catch (final ArgumentParserException e) {
175 parser.handleError(e);
182 private static class ConfigGenerator {
183 public static final String NETCONF_CONNECTOR_XML = "/initial/99-netconf-connector.xml";
184 public static final String NETCONF_CONNECTOR_NAME = "controller-config";
185 public static final String NETCONF_CONNECTOR_PORT = "1830";
186 public static final String NETCONF_CONNECTOR_ADDRESS = "127.0.0.1";
187 public static final String NETCONF_USE_SSH = "false";
188 public static final String SIM_DEVICE_SUFFIX = "-sim-device";
190 private final File directory;
191 private final List<Integer> openDevices;
193 public ConfigGenerator(final File directory, final List<Integer> openDevices) {
194 this.directory = directory;
195 this.openDevices = openDevices;
198 public void generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout, final String address) {
199 if(directory.exists() == false) {
200 checkState(directory.mkdirs(), "Unable to create folder %s" + directory);
203 try(InputStream stream = Main.class.getResourceAsStream(NETCONF_CONNECTOR_XML)) {
204 checkNotNull(stream, "Cannot load %s", NETCONF_CONNECTOR_XML);
205 String configBlueprint = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
207 // TODO make address configurable
208 checkState(configBlueprint.contains(NETCONF_CONNECTOR_NAME));
209 checkState(configBlueprint.contains(NETCONF_CONNECTOR_PORT));
210 checkState(configBlueprint.contains(NETCONF_USE_SSH));
211 checkState(configBlueprint.contains(NETCONF_CONNECTOR_ADDRESS));
212 configBlueprint = configBlueprint.replace(NETCONF_CONNECTOR_NAME, "%s");
213 configBlueprint = configBlueprint.replace(NETCONF_CONNECTOR_ADDRESS, "%s");
214 configBlueprint = configBlueprint.replace(NETCONF_CONNECTOR_PORT, "%s");
215 configBlueprint = configBlueprint.replace(NETCONF_USE_SSH, "%s");
217 final String before = configBlueprint.substring(0, configBlueprint.indexOf("<module>"));
218 final String middleBlueprint = configBlueprint.substring(configBlueprint.indexOf("<module>"), configBlueprint.indexOf("</module>"));
219 final String after = configBlueprint.substring(configBlueprint.indexOf("</module>") + "</module>".length());
221 int connectorCount = 0;
222 Integer batchStart = null;
223 StringBuilder b = new StringBuilder();
226 for (final Integer openDevice : openDevices) {
227 if(batchStart == null) {
228 batchStart = openDevice;
231 final String name = String.valueOf(openDevice) + SIM_DEVICE_SUFFIX;
232 String configContent = String.format(middleBlueprint, name, address, String.valueOf(openDevice), String.valueOf(!useSsh));
233 configContent = String.format("%s%s%d%s\n%s\n", configContent, "<connection-timeout-millis>", generateConfigsTimeout, "</connection-timeout-millis>", "</module>");
235 b.append(configContent);
237 if(connectorCount == batchSize) {
239 Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevice)), Charsets.UTF_8);
241 b = new StringBuilder();
248 if(connectorCount != 0) {
250 Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevices.get(openDevices.size() - 1))), Charsets.UTF_8);
253 LOG.info("Config files generated in {}", directory);
254 } catch (final IOException e) {
255 throw new RuntimeException("Unable to generate config files", e);