eb6363227d8d40d08165f86eace8ac72933667b9
[netconf.git] / netconf / tools / netconf-testtool / src / main / java / org / opendaylight / netconf / test / tool / TesttoolParameters.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.netconf.test.tool;
10
11 import static com.google.common.base.Preconditions.checkArgument;
12
13 import com.google.common.base.Charsets;
14 import com.google.common.base.Preconditions;
15 import com.google.common.io.CharStreams;
16 import com.google.common.io.Files;
17 import java.io.File;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.InputStreamReader;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.concurrent.TimeUnit;
24 import java.util.regex.Pattern;
25 import net.sourceforge.argparse4j.ArgumentParsers;
26 import net.sourceforge.argparse4j.annotation.Arg;
27 import net.sourceforge.argparse4j.inf.ArgumentParser;
28 import net.sourceforge.argparse4j.inf.ArgumentParserException;
29
30 public class TesttoolParameters {
31
32     private static final String HOST_KEY = "{HOST}";
33     private static final String PORT_KEY = "{PORT}";
34     private static final String SSH = "{SSH}";
35     private static final String ADDRESS_PORT = "{ADDRESS:PORT}";
36     private static final String dest = "http://{ADDRESS:PORT}/restconf/config/network-topology:network-topology/topology/topology-netconf/node/{PORT}-sim-device";
37
38     private static final String RESOURCE = "/config-template.xml";
39     private InputStream stream;
40
41     @Arg(dest = "edit-content")
42     public File editContent;
43
44     @Arg(dest = "async")
45     public boolean async;
46
47     @Arg(dest = "thread-amount")
48     public int threadAmount;
49
50     @Arg(dest = "throttle")
51     public int throttle;
52
53     @Arg(dest = "auth")
54     public ArrayList<String> auth;
55
56     @Arg(dest = "controller-destination")
57     public String controllerDestination;
58
59     @Arg(dest = "schemas-dir")
60     public File schemasDir;
61
62     @Arg(dest = "devices-count")
63     public int deviceCount;
64
65     @Arg(dest = "devices-per-port")
66     public int devicesPerPort;
67
68     @Arg(dest = "starting-port")
69     public int startingPort;
70
71     @Arg(dest = "generate-config-connection-timeout")
72     public int generateConfigsTimeout;
73
74     @Arg(dest = "generate-config-address")
75     public String generateConfigsAddress;
76
77     @Arg(dest = "distro-folder")
78     public File distroFolder;
79
80     @Arg(dest = "generate-configs-batch-size")
81     public int generateConfigBatchSize;
82
83     @Arg(dest = "ssh")
84     public boolean ssh;
85
86     @Arg(dest = "exi")
87     public boolean exi;
88
89     @Arg(dest = "debug")
90     public boolean debug;
91
92     @Arg(dest = "notification-file")
93     public File notificationFile;
94
95     @Arg(dest = "md-sal")
96     public boolean mdSal;
97
98     @Arg(dest = "initial-config-xml-file")
99     public File initialConfigXMLFile;
100
101     @Arg(dest = "time-out")
102     public long timeOut;
103
104     static ArgumentParser getParser() {
105         final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testtool");
106
107         parser.description("netconf testtool");
108
109         parser.addArgument("--edit-content")
110                 .type(String.class)
111                 .dest("edit-content");
112
113         parser.addArgument("--async-requests")
114                 .type(Boolean.class)
115                 .setDefault(false)
116                 .dest("async");
117
118         parser.addArgument("--thread-amount")
119                 .type(Integer.class)
120                 .setDefault(1)
121                 .dest("thread-amount");
122
123         parser.addArgument("--throttle")
124                 .type(Integer.class)
125                 .setDefault(5000)
126                 .help("Maximum amount of async requests that can be open at a time, " +
127                         "with mutltiple threads this gets divided among all threads")
128                 .dest("throttle");
129
130         parser.addArgument("--auth")
131                 .nargs(2)
132                 .help("Username and password for HTTP basic authentication in order username password.")
133                 .dest("auth");
134
135         parser.addArgument("--controller-destination")
136                 .type(String.class)
137                 .help("Ip address and port of controller. Must be in following format <ip>:<port> "+
138                       "if available it will be used for spawning netconf connectors via topology configuration as "+
139                       "a part of URI. Example (http://<controller destination>/restconf/config/network-topology:network-topology/topology/topology-netconf/node/<node-id>)"+
140                       "otherwise it will just start simulated devices and skip the execution of PUT requests")
141                 .dest("controller-destination");
142
143         parser.addArgument("--device-count")
144                 .type(Integer.class)
145                 .setDefault(1)
146                 .help("Number of simulated netconf devices to spin. This is the number of actual ports open for the devices.")
147                 .dest("devices-count");
148
149         parser.addArgument("--devices-per-port")
150                 .type(Integer.class)
151                 .setDefault(1)
152                 .help("Amount of config files generated per port to spoof more devices then are actually running")
153                 .dest("devices-per-port");
154
155         parser.addArgument("--schemas-dir")
156                 .type(File.class)
157                 .help("Directory containing yang schemas to describe simulated devices. Some schemas e.g. netconf monitoring and inet types are included by default")
158                 .dest("schemas-dir");
159
160         parser.addArgument("--notification-file")
161                 .type(File.class)
162                 .help("Xml file containing notifications that should be sent to clients after create subscription is called")
163                 .dest("notification-file");
164
165         parser.addArgument("--initial-config-xml-file")
166                 .type(File.class)
167                 .help("Xml file containing initial simulatted configuration to be returned via get-config rpc")
168                 .dest("initial-config-xml-file");
169
170         parser.addArgument("--starting-port")
171                 .type(Integer.class)
172                 .setDefault(17830)
173                 .help("First port for simulated device. Each other device will have previous+1 port number")
174                 .dest("starting-port");
175
176         parser.addArgument("--generate-config-connection-timeout")
177                 .type(Integer.class)
178                 .setDefault((int) TimeUnit.MINUTES.toMillis(30))
179                 .help("Timeout to be generated in initial config files")
180                 .dest("generate-config-connection-timeout");
181
182         parser.addArgument("--generate-config-address")
183                 .type(String.class)
184                 .setDefault("127.0.0.1")
185                 .help("Address to be placed in generated configs")
186                 .dest("generate-config-address");
187
188         parser.addArgument("--generate-configs-batch-size")
189                 .type(Integer.class)
190                 .setDefault(4000)
191                 .help("Number of connector configs per generated file")
192                 .dest("generate-configs-batch-size");
193
194         parser.addArgument("--distribution-folder")
195                 .type(File.class)
196                 .help("Directory where the karaf distribution for controller is located")
197                 .dest("distro-folder");
198
199         parser.addArgument("--ssh")
200                 .type(Boolean.class)
201                 .setDefault(true)
202                 .help("Whether to use ssh for transport or just pure tcp")
203                 .dest("ssh");
204
205         parser.addArgument("--exi")
206                 .type(Boolean.class)
207                 .setDefault(true)
208                 .help("Whether to use exi to transport xml content")
209                 .dest("exi");
210
211         parser.addArgument("--debug")
212                 .type(Boolean.class)
213                 .setDefault(false)
214                 .help("Whether to use debug log level instead of INFO")
215                 .dest("debug");
216
217         parser.addArgument("--md-sal")
218                 .type(Boolean.class)
219                 .setDefault(false)
220                 .help("Whether to use md-sal datastore instead of default simulated datastore.")
221                 .dest("md-sal");
222
223         parser.addArgument("--time-out")
224                 .type(long.class)
225                 .setDefault(20)
226                 .help("the maximum time in seconds for executing each PUT request")
227                 .dest("time-out");
228
229         return parser;
230     }
231
232     public static TesttoolParameters parseArgs(final String[] args, final ArgumentParser parser) {
233         final TesttoolParameters opt = new TesttoolParameters();
234         try {
235             parser.parseArgs(args, opt);
236             return opt;
237         } catch (final ArgumentParserException e) {
238             parser.handleError(e);
239         }
240
241         System.exit(1);
242         return null;
243     }
244
245     void validate() {
246         if (editContent == null) {
247             stream = TesttoolParameters.class.getResourceAsStream(RESOURCE);
248         } else {
249             Preconditions.checkArgument(!editContent.isDirectory(), "Edit content file is a dir");
250             Preconditions.checkArgument(editContent.canRead(), "Edit content file is unreadable");
251         }
252
253         if (controllerDestination != null) {
254             Preconditions.checkArgument(controllerDestination.contains(":"), "Controller Destination needs to be in a following format <ip>:<port>");
255             String[] parts = controllerDestination.split(Pattern.quote(":"));
256             Preconditions.checkArgument(Integer.parseInt(parts[1]) > 0, "Port =< 0");
257         }
258
259         checkArgument(deviceCount > 0, "Device count has to be > 0");
260         checkArgument(startingPort > 1023, "Starting port has to be > 1023");
261         checkArgument(devicesPerPort > 0, "Atleast one device per port needed");
262
263         if (schemasDir != null) {
264             checkArgument(schemasDir.exists(), "Schemas dir has to exist");
265             checkArgument(schemasDir.isDirectory(), "Schemas dir has to be a directory");
266             checkArgument(schemasDir.canRead(), "Schemas dir has to be readable");
267         }
268     }
269
270     public ArrayList<ArrayList<Execution.DestToPayload>> getThreadsPayloads(List<Integer> openDevices) {
271         final String editContentString;
272         try {
273             if(stream == null)
274             {
275                 editContentString = Files.toString(editContent, Charsets.UTF_8);
276             } else {
277                 editContentString = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
278             }
279         } catch (final IOException e) {
280             throw new IllegalArgumentException("Cannot read content of " + editContent);
281         }
282
283         final ArrayList<ArrayList<Execution.DestToPayload>> allThreadsPayloads = new ArrayList<>();
284         for (int i = 0; i < threadAmount; i++) {
285             final ArrayList<Execution.DestToPayload> payloads = new ArrayList<>();
286             for (int j = 0; j < openDevices.size(); j++) {
287                 final StringBuilder destBuilder = new StringBuilder(dest);
288                 destBuilder.replace(destBuilder.indexOf(ADDRESS_PORT), destBuilder.indexOf(ADDRESS_PORT) + ADDRESS_PORT.length(), controllerDestination)
289                         .replace(destBuilder.indexOf(PORT_KEY), destBuilder.indexOf(PORT_KEY) + PORT_KEY.length(), Integer.toString(openDevices.get(j)));
290                 payloads.add(new Execution.DestToPayload(destBuilder.toString(), prepareMessage(openDevices.get(j), editContentString)));
291             }
292             allThreadsPayloads.add(payloads);
293         }
294
295         return allThreadsPayloads;
296     }
297
298     private String prepareMessage(final int openDevice, final String editContentString) {
299         StringBuilder messageBuilder = new StringBuilder(editContentString);
300
301         if (editContentString.contains(HOST_KEY)) {
302             messageBuilder.replace(messageBuilder.indexOf(HOST_KEY), messageBuilder.indexOf(HOST_KEY) + HOST_KEY.length(), generateConfigsAddress);
303         }
304         if (editContentString.contains(PORT_KEY)) {
305             while (messageBuilder.indexOf(PORT_KEY) != -1)
306                 messageBuilder.replace(messageBuilder.indexOf(PORT_KEY), messageBuilder.indexOf(PORT_KEY) + PORT_KEY.length(), Integer.toString(openDevice));
307         }
308         if (editContentString.contains(SSH)) {
309             messageBuilder.replace(messageBuilder.indexOf(SSH), messageBuilder.indexOf(SSH) + SSH.length(), Boolean.toString(ssh));
310         }
311         return messageBuilder.toString();
312     }
313 }