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-configs-dir")
57 public File generateConfigsDir;
59 @Arg(dest = "generate-configs-batch-size")
60 public int generateConfigBatchSize;
68 static ArgumentParser getParser() {
69 final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool");
70 parser.addArgument("--devices-count")
74 .help("Number of simulated netconf devices to spin")
75 .dest("devices-count");
77 parser.addArgument("--schemas-dir")
80 .help("Directory containing yang schemas to describe simulated devices")
83 parser.addArgument("--starting-port")
86 .help("First port for simulated device. Each other device will have previous+1 port number")
87 .dest("starting-port");
89 parser.addArgument("--generate-config-connection-timeout")
91 .setDefault((int)TimeUnit.MINUTES.toMillis(5))
92 .help("Timeout to be generated in initial config files")
93 .dest("generate-config-connection-timeout");
95 parser.addArgument("--generate-configs-batch-size")
98 .help("Number of connector configs per generated file")
99 .dest("generate-configs-batch-size");
101 parser.addArgument("--generate-configs-dir")
103 .help("Directory where initial config files for ODL distribution should be generated")
104 .dest("generate-configs-dir");
106 parser.addArgument("--ssh")
109 .help("Whether to use ssh for transport or just pure tcp")
112 parser.addArgument("--exi")
115 .help("Whether to use exi to transport xml content")
122 checkArgument(deviceCount > 0, "Device count has to be > 0");
123 checkArgument(startingPort > 1024, "Starting port has to be > 1024");
125 checkArgument(schemasDir.exists(), "Schemas dir has to exist");
126 checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory");
127 checkArgument(schemasDir.canRead(), "Schemas dir has to be readable");
131 public static void main(final String[] args) {
132 ch.ethz.ssh2.log.Logger.enabled = true;
134 final Params params = parseArgs(args, Params.getParser());
137 final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator();
139 final List<Integer> openDevices = netconfDeviceSimulator.start(params);
140 if(params.generateConfigsDir != null) {
141 new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout);
143 } catch (final Exception e) {
144 LOG.error("Unhandled exception", e);
145 netconfDeviceSimulator.close();
150 synchronized (netconfDeviceSimulator) {
152 netconfDeviceSimulator.wait();
153 } catch (final InterruptedException e) {
154 throw new RuntimeException(e);
160 private static Params parseArgs(final String[] args, final ArgumentParser parser) {
161 final Params opt = new Params();
163 parser.parseArgs(args, opt);
165 } catch (final ArgumentParserException e) {
166 parser.handleError(e);
173 private static class ConfigGenerator {
174 public static final String NETCONF_CONNECTOR_XML = "/initial/99-netconf-connector.xml";
175 public static final String NETCONF_CONNECTOR_NAME = "controller-config";
176 public static final String NETCONF_CONNECTOR_PORT = "1830";
177 public static final String NETCONF_USE_SSH = "false";
178 public static final String SIM_DEVICE_SUFFIX = "-sim-device";
180 private final File directory;
181 private final List<Integer> openDevices;
183 public ConfigGenerator(final File directory, final List<Integer> openDevices) {
184 this.directory = directory;
185 this.openDevices = openDevices;
188 public void generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout) {
189 if(directory.exists() == false) {
190 checkState(directory.mkdirs(), "Unable to create folder %s" + directory);
193 try(InputStream stream = Main.class.getResourceAsStream(NETCONF_CONNECTOR_XML)) {
194 checkNotNull(stream, "Cannot load %s", NETCONF_CONNECTOR_XML);
195 String configBlueprint = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
197 // TODO make address configurable
198 checkState(configBlueprint.contains(NETCONF_CONNECTOR_NAME));
199 checkState(configBlueprint.contains(NETCONF_CONNECTOR_PORT));
200 checkState(configBlueprint.contains(NETCONF_USE_SSH));
201 configBlueprint = configBlueprint.replace(NETCONF_CONNECTOR_NAME, "%s");
202 configBlueprint = configBlueprint.replace(NETCONF_CONNECTOR_PORT, "%s");
203 configBlueprint = configBlueprint.replace(NETCONF_USE_SSH, "%s");
205 final String before = configBlueprint.substring(0, configBlueprint.indexOf("<module>"));
206 final String middleBlueprint = configBlueprint.substring(configBlueprint.indexOf("<module>"), configBlueprint.indexOf("</module>"));
207 final String after = configBlueprint.substring(configBlueprint.indexOf("</module>") + "</module>".length());
209 int connectorCount = 0;
210 Integer batchStart = null;
211 StringBuilder b = new StringBuilder();
214 for (final Integer openDevice : openDevices) {
215 if(batchStart == null) {
216 batchStart = openDevice;
219 final String name = String.valueOf(openDevice) + SIM_DEVICE_SUFFIX;
220 String configContent = String.format(middleBlueprint, name, String.valueOf(openDevice), String.valueOf(!useSsh));
221 configContent = String.format("%s%s%d%s\n%s\n", configContent, "<connection-timeout-millis>", generateConfigsTimeout, "</connection-timeout-millis>", "</module>");
223 b.append(configContent);
225 if(connectorCount == batchSize) {
227 Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevice)), Charsets.UTF_8);
229 b = new StringBuilder();
236 if(connectorCount != 0) {
238 Files.write(b.toString(), new File(directory, String.format("simulated-devices_%d-%d.xml", batchStart, openDevices.get(openDevices.size() - 1))), Charsets.UTF_8);
241 LOG.info("Config files generated in {}", directory);
242 } catch (final IOException e) {
243 throw new RuntimeException("Unable to generate config files", e);