Merge "Avoid relying on the timezone"
authorMaros Marsalek <mmarsale@cisco.com>
Thu, 17 Mar 2016 10:12:19 +0000 (10:12 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 17 Mar 2016 10:12:19 +0000 (10:12 +0000)
21 files changed:
netconf/abstract-topology/pom.xml
netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java
netconf/messagebus-netconf/src/main/java/org/opendaylight/netconf/messagebus/eventsources/netconf/NetconfEventSource.java
netconf/netconf-impl/src/main/java/org/opendaylight/netconf/impl/NetconfServerSessionListener.java
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java
netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/Get.java
netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/NotificationsTransformUtil.java
netconf/netconf-topology/src/test/resources/test.conf
netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/NetconfUtil.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/package-info.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfMessageTransformUtil.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/package-info.java
netconf/tools/netconf-testtool/pom.xml
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/Main.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/ScaleUtil.java [new file with mode: 0644]
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/Parameters.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RestPerfClient.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/scale/util/ScaleUtilParameters.java [new file with mode: 0644]
netconf/tools/netconf-testtool/src/main/resources/logback.xml

index 827e4de1b7317e0eaeb926b05605de6f7a612a98..b6d75095377ea1a52ce41cee1c017d744df6d844 100644 (file)
     </dependencyManagement>
 
     <properties>
-        <!-- FIXME: should be inherited from odlparent -->
-        <akka.version>2.3.14</akka.version>
-        <scala.major.version>2.11</scala.major.version>
-        <scala.minor.version>7</scala.minor.version>
     </properties>
 
     <dependencies>
         <dependency>
             <groupId>org.scala-lang</groupId>
             <artifactId>scala-library</artifactId>
-            <version>${scala.major.version}.${scala.minor.version}</version>
         </dependency>
         <dependency>
             <groupId>com.typesafe.akka</groupId>
-            <artifactId>akka-actor_${scala.major.version}</artifactId>
-            <version>${akka.version}</version>
+            <artifactId>akka-actor_${scala.version}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.typesafe.akka</groupId>
-            <artifactId>akka-remote_${scala.major.version}</artifactId>
-            <version>${akka.version}</version>
+            <artifactId>akka-remote_${scala.version}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.typesafe.akka</groupId>
-            <artifactId>akka-cluster_${scala.major.version}</artifactId>
-            <version>${akka.version}</version>
+            <artifactId>akka-cluster_${scala.version}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.typesafe.akka</groupId>
-            <artifactId>akka-osgi_${scala.major.version}</artifactId>
-            <version>${akka.version}</version>
+            <artifactId>akka-osgi_${scala.version}</artifactId>
         </dependency>
         <dependency>
             <groupId>com.typesafe</groupId>
index 33cde89cd9eeebbe1f1f13622a3db692e394284c..4f0a53a43ca68d502d0dafa857529bf38ae8ddcd 100644 (file)
@@ -8,13 +8,18 @@
 
 package org.opendaylight.netconf.topology.util;
 
+import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -26,32 +31,43 @@ public final class SalNodeWriter implements NodeWriter {
 
     private static final Logger LOG = LoggerFactory.getLogger(SalNodeWriter.class);
 
-    private final DataBroker dataBroker;
     private final String topologyId;
 
+    private final BindingTransactionChain transactionChain;
     public SalNodeWriter(final DataBroker dataBroker, final String topologyId) {
-        this.dataBroker = dataBroker;
         this.topologyId = topologyId;
+        this.transactionChain = Preconditions.checkNotNull(dataBroker).createTransactionChain(new TransactionChainListener() {
+            @Override
+            public void onTransactionChainFailed(TransactionChain<?, ?> transactionChain, AsyncTransaction<?, ?> transaction, Throwable cause) {
+                LOG.error("{}: TransactionChain({}) {} FAILED!", transactionChain,
+                        transaction.getIdentifier(), cause);
+                throw new IllegalStateException("Abstract topology writer TransactionChain(" + transactionChain + ") not committed correctly", cause);
+            }
+
+            @Override
+            public void onTransactionChainSuccessful(TransactionChain<?, ?> transactionChain) {
+                LOG.trace("Abstract topology writer TransactionChain({}) SUCCESSFUL", transactionChain);
+            }
+        });
     }
 
-    //FIXME change to txChains
     @Override public void init(@Nonnull final NodeId id, @Nonnull final Node operationalDataNode) {
         // put into Datastore
-        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
+        final WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
         wTx.put(LogicalDatastoreType.OPERATIONAL, TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId), operationalDataNode);
         commitTransaction(wTx, id, "init");
     }
 
     @Override public void update(@Nonnull final NodeId id, @Nonnull final Node operationalDataNode) {
         // merge
-        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
+        final WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
         wTx.put(LogicalDatastoreType.OPERATIONAL, TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId), operationalDataNode);
         commitTransaction(wTx, id, "update");
     }
 
     @Override public void delete(@Nonnull final NodeId id) {
         // delete
-        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
+        final WriteTransaction wTx = transactionChain.newWriteOnlyTransaction();
         wTx.delete(LogicalDatastoreType.OPERATIONAL, TopologyUtil.createTopologyNodeListPath(new NodeKey(id), topologyId));
         commitTransaction(wTx, id, "delete");
     }
index a085088571229ec8700a74f14f397bb891bd7878..28300753b3e0d8fafee3c9c3098b68999d21766e 100644 (file)
@@ -41,7 +41,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
 import org.opendaylight.controller.messagebus.app.util.TopicDOMNotification;
 import org.opendaylight.controller.messagebus.app.util.Util;
 import org.opendaylight.controller.messagebus.spi.EventSource;
-import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.util.NetconfUtil;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.NotificationPattern;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.TopicId;
 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.messagebus.eventaggregator.rev141202.TopicNotification;
@@ -287,7 +287,7 @@ public class NetconfEventSource implements EventSource, DOMNotificationListener
         final SchemaContext context = getDOMMountPoint().getSchemaContext();
         final SchemaPath schemaPath = body.getType();
         try {
-            NetconfMessageTransformUtil.writeNormalizedNode(body.getBody(), result, schemaPath, context);
+            NetconfUtil.writeNormalizedNode(body.getBody(), result, schemaPath, context);
             return Builders.anyXmlBuilder().withNodeIdentifier(PAYLOAD_ARG).withValue(new DOMSource(element)).build();
         } catch (IOException | XMLStreamException e) {
             LOG.error("Unable to encapsulate notification.", e);
index ae0a07f4ef31bc0a990af7288f86a01a324fd5b9..a1a16f426c17c7316a2f6c082644b071bbef8d99 100644 (file)
@@ -125,8 +125,7 @@ public class NetconfServerSessionListener implements NetconfSessionListener<Netc
              * Severity: error Error-info: <bad-element> : name of the
              * unexpected element Description: An unexpected element is present.
              */
-            // TODO add message to error info
-            throw new DocumentedException("Unknown tag " + rootNode.getNodeName(),
+            throw new DocumentedException("Unknown tag " + rootNode.getNodeName() + " in message:\n" + netconfMessage,
                     DocumentedException.ErrorType.protocol, DocumentedException.ErrorTag.unknown_element,
                     DocumentedException.ErrorSeverity.error, ImmutableMap.of("bad-element",
                             rootNode.getNodeName()));
index c8d4b90f39ed5854fb27791c173d3f5e02f67967..6219f91b2d9998a6c2d2027a457f615f14de69cb 100644 (file)
@@ -12,10 +12,9 @@ import java.io.IOException;
 import org.apache.sshd.ClientSession;
 import org.apache.sshd.client.future.AuthFuture;
 
-//TODO checkstyle reports imports only used in javadoc as not used, readd link to AsyncSshHandler once this is no longer the case
 /**
  * Class Providing username/password authentication option to
- * AsyncSshHandler
+ * {@link org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandler}
  */
 public class LoginPassword extends AuthenticationHandler {
     private final String username;
index 9ed609da5b0407695e2932a4c0ef36aac3ada16e..78db2f6c69c88b1244ffcbcf6347aa55c8542527 100644 (file)
@@ -15,11 +15,12 @@ import javax.xml.transform.dom.DOMResult;
 import org.opendaylight.controller.config.util.xml.DocumentedException;
 import org.opendaylight.controller.config.util.xml.XmlElement;
 import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
-import org.opendaylight.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.netconf.mapping.api.NetconfOperationChainedExecution;
 import org.opendaylight.netconf.notifications.NetconfNotificationRegistry;
+import org.opendaylight.netconf.util.NetconfUtil;
+import org.opendaylight.netconf.util.mapping.AbstractNetconfOperation;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.Netconf;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.NetconfBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.Streams;
@@ -68,7 +69,7 @@ public class Get extends AbstractNetconfOperation implements AutoCloseable {
         final DOMResult result = new DOMResult(getPlaceholder(partialResponse));
 
         try {
-            NotificationsTransformUtil.writeNormalizedNode(normalized, result, SchemaPath.ROOT);
+            NetconfUtil.writeNormalizedNode(normalized, result, SchemaPath.ROOT, NotificationsTransformUtil.NOTIFICATIONS_SCHEMA_CTX);
         } catch (final XMLStreamException | IOException e) {
             throw new IllegalStateException("Unable to serialize " + netconfSubtree, e);
         }
index 0aff22803ce10266e27a3cd11807a9d41c298d14..0ac484920320fe1383fda1d6906e97b2ae5a7a09 100644 (file)
@@ -17,12 +17,11 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.Date;
 import javassist.ClassPool;
-import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
 import javax.xml.transform.dom.DOMResult;
 import org.opendaylight.controller.config.util.xml.XmlUtil;
 import org.opendaylight.netconf.notifications.NetconfNotification;
+import org.opendaylight.netconf.util.NetconfUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.$YangModuleInfoImpl;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
 import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
@@ -31,10 +30,6 @@ import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedCon
 import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
 import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -50,14 +45,11 @@ public final class NotificationsTransformUtil {
 
     static final SchemaContext NOTIFICATIONS_SCHEMA_CTX;
     static final BindingNormalizedNodeCodecRegistry CODEC_REGISTRY;
-    static final XMLOutputFactory XML_FACTORY;
     static final RpcDefinition CREATE_SUBSCRIPTION_RPC;
 
     static final SchemaPath CAPABILITY_CHANGE_SCHEMA_PATH = SchemaPath.create(true, NetconfCapabilityChange.QNAME);
 
     static {
-        XML_FACTORY = XMLOutputFactory.newFactory();
-        XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
 
         final ModuleInfoBackedContext moduleInfoBackedContext = ModuleInfoBackedContext.create();
         moduleInfoBackedContext.addModuleInfos(Collections.singletonList($YangModuleInfoImpl.getInstance()));
@@ -99,7 +91,7 @@ public final class NotificationsTransformUtil {
         final ContainerNode containerNode = CODEC_REGISTRY.toNormalizedNodeNotification(capabilityChange);
         final DOMResult result = new DOMResult(XmlUtil.newDocument());
         try {
-            writeNormalizedNode(containerNode, result, CAPABILITY_CHANGE_SCHEMA_PATH);
+            NetconfUtil.writeNormalizedNode(containerNode, result, CAPABILITY_CHANGE_SCHEMA_PATH, NOTIFICATIONS_SCHEMA_CTX);
         } catch (final XMLStreamException| IOException e) {
             throw new IllegalStateException("Unable to serialize " + capabilityChange, e);
         }
@@ -109,33 +101,4 @@ public final class NotificationsTransformUtil {
                 new NetconfNotification(node);
     }
 
-    static void writeNormalizedNode(final NormalizedNode<?, ?> normalized, final DOMResult result, final SchemaPath schemaPath) throws IOException, XMLStreamException {
-        NormalizedNodeWriter normalizedNodeWriter = null;
-        NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
-        XMLStreamWriter writer = null;
-        try {
-            writer = XML_FACTORY.createXMLStreamWriter(result);
-            normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, NOTIFICATIONS_SCHEMA_CTX, schemaPath);
-            normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter);
-
-            normalizedNodeWriter.write(normalized);
-
-            normalizedNodeWriter.flush();
-        } finally {
-            try {
-                if(normalizedNodeWriter != null) {
-                    normalizedNodeWriter.close();
-                }
-                if(normalizedNodeStreamWriter != null) {
-                    normalizedNodeStreamWriter.close();
-                }
-                if(writer != null) {
-                    writer.close();
-                }
-            } catch (final Exception e) {
-                LOG.warn("Unable to close resource properly", e);
-            }
-        }
-    }
-
 }
index 3346d64ad8ee19f6b75da0681ed0a07e7aaf9493..b8c72947b5f90f3fcf768473929014addb765001 100644 (file)
@@ -1,7 +1,5 @@
 akka {
 
-  version = "2.3.14"
-
   actor {
     provider = "akka.cluster.ClusterActorRefProvider"
 
@@ -21,5 +19,4 @@ akka {
       hostname = "127.0.0.1"
     }
   }
-
 }
index 9b47c58e571e0b10d3df3c6482edd2f8ac4409e1..0e8b9aeec4592b0f98dc5a4d719db0e44933c7c4 100644 (file)
@@ -8,11 +8,22 @@
 package org.opendaylight.netconf.util;
 
 import com.google.common.base.Preconditions;
+import java.io.IOException;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMResult;
 import org.opendaylight.controller.config.util.xml.DocumentedException;
 import org.opendaylight.controller.config.util.xml.XmlElement;
 import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
 import org.opendaylight.controller.config.util.xml.XmlUtil;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -20,6 +31,12 @@ import org.w3c.dom.Document;
 public final class NetconfUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfUtil.class);
+    public static final XMLOutputFactory XML_FACTORY;
+
+    static {
+        XML_FACTORY = XMLOutputFactory.newFactory();
+        XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
+    }
 
     private NetconfUtil() {}
 
@@ -34,4 +51,24 @@ public final class NetconfUtil {
         throw new IllegalStateException("Can not load last configuration. Operation failed: "
                 + XmlUtil.toString(response));
     }
+
+    public static void writeNormalizedNode(final NormalizedNode<?, ?> normalized, final DOMResult result, final SchemaPath schemaPath, final SchemaContext context)
+            throws IOException, XMLStreamException {
+        final XMLStreamWriter writer = XML_FACTORY.createXMLStreamWriter(result);
+        try (
+             final NormalizedNodeStreamWriter normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, context, schemaPath);
+             final NormalizedNodeWriter normalizedNodeWriter =  NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter)
+        ) {
+            normalizedNodeWriter.write(normalized);
+            normalizedNodeWriter.flush();
+        } finally {
+            try {
+                if(writer != null) {
+                    writer.close();
+                }
+            } catch (final Exception e) {
+                LOG.warn("Unable to close resource properly", e);
+            }
+        }
+    }
 }
index ddc3e4a2bf84320dd029204d43722804b91c98f7..399cdf0f3b5f715613562d44419e2dfe32b052c0 100644 (file)
@@ -7,8 +7,6 @@
  */
 
 /**
- * General API for remote connectors e.g. netconf connector
- *
- * TODO extract into separate bundle when another connector is implemented e.g. restconf connector
+ * API for netconf connector
  */
 package org.opendaylight.netconf.sal.connect.api;
index 6cb51966bace09853cb871a6324ddc4fa2692fe2..68805c40d4bcbff8fdb8a594d6fab11411c3c017 100644 (file)
@@ -37,8 +37,6 @@ public class NetconfDeviceNotificationService implements DOMNotificationService
             listeners.put(type, listener);
         }
 
-        // FIXME this should invoke create-subscription rpc on the remote device for a given notification
-
         return new ListenerRegistration<T>() {
             @Override
             public void close() {
index f5ebbbbe5098d529a532c9287273ea7522937b7b..668415aa6b1a3387b3d88a80e44fa634637e3ce0 100644 (file)
@@ -45,6 +45,7 @@ import org.opendaylight.netconf.notifications.NetconfNotification;
 import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
 import org.opendaylight.netconf.sal.connect.util.MessageCounter;
+import org.opendaylight.netconf.util.NetconfUtil;
 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -299,7 +300,7 @@ public class NetconfMessageTransformer implements MessageTransformer<NetconfMess
 
     private static void writeNormalizedRpc(final ContainerNode normalized, final DOMResult result,
             final SchemaPath schemaPath, final SchemaContext baseNetconfCtx) throws IOException, XMLStreamException {
-        final XMLStreamWriter writer = NetconfMessageTransformUtil.XML_FACTORY.createXMLStreamWriter(result);
+        final XMLStreamWriter writer = NetconfUtil.XML_FACTORY.createXMLStreamWriter(result);
         try {
             try (final NormalizedNodeStreamWriter normalizedNodeStreamWriter =
                     XMLStreamNormalizedNodeStreamWriter.create(writer, baseNetconfCtx, schemaPath)) {
index 89472b7b6c022d712ca6330703e74cf860f2fbef..a0622d719c41fa60a0ed1c4d5823dc5a9a0ef802 100644 (file)
@@ -17,14 +17,13 @@ import java.util.AbstractMap;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
-import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
 import javax.xml.transform.dom.DOMResult;
 import javax.xml.transform.dom.DOMSource;
 import org.opendaylight.controller.config.util.xml.XmlUtil;
 import org.opendaylight.netconf.api.NetconfDocumentedException;
 import org.opendaylight.netconf.api.NetconfMessage;
+import org.opendaylight.netconf.util.NetconfUtil;
 import org.opendaylight.netconf.util.messages.NetconfMessageUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.edit.config.input.EditContent;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInput;
@@ -40,9 +39,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
-import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
@@ -60,12 +56,6 @@ public class NetconfMessageTransformUtil {
     private static final Logger LOG= LoggerFactory.getLogger(NetconfMessageTransformUtil.class);
 
     public static final String MESSAGE_ID_ATTR = "message-id";
-    public static final XMLOutputFactory XML_FACTORY;
-
-    static {
-        XML_FACTORY = XMLOutputFactory.newFactory();
-        XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
-    }
 
     public static final QName CREATE_SUBSCRIPTION_RPC_QNAME = QName.cachedReference(QName.create(CreateSubscriptionInput.QNAME, "create-subscription"));
     private static final String SUBTREE = "subtree";
@@ -168,7 +158,7 @@ public class NetconfMessageTransformUtil {
         element.setAttributeNS(NETCONF_FILTER_QNAME.getNamespace().toString(), NETCONF_TYPE_QNAME.getLocalName(), "subtree");
 
         try {
-            writeNormalizedNode(filterContent, new DOMResult(element), SchemaPath.ROOT, ctx);
+            NetconfUtil.writeNormalizedNode(filterContent, new DOMResult(element), SchemaPath.ROOT, ctx);
         } catch (IOException | XMLStreamException e) {
             throw new IllegalStateException("Unable to serialize filter element for path " + identifier, e);
         }
@@ -291,7 +281,7 @@ public class NetconfMessageTransformUtil {
 
         final Element element = XmlUtil.createElement(BLANK_DOCUMENT, NETCONF_CONFIG_QNAME.getLocalName(), Optional.of(NETCONF_CONFIG_QNAME.getNamespace().toString()));
         try {
-            writeNormalizedNode(configContent, new DOMResult(element), SchemaPath.ROOT, ctx);
+            NetconfUtil.writeNormalizedNode(configContent, new DOMResult(element), SchemaPath.ROOT, ctx);
         } catch (IOException | XMLStreamException e) {
             throw new IllegalStateException("Unable to serialize edit config content element for path " + dataPath, e);
         }
@@ -305,34 +295,4 @@ public class NetconfMessageTransformUtil {
         return SchemaPath.create(true, rpc);
     }
 
-    // FIXME similar code is in netconf-notifications-impl , DRY
-    public static void writeNormalizedNode(final NormalizedNode<?, ?> normalized, final DOMResult result, final SchemaPath schemaPath, final SchemaContext context)
-            throws IOException, XMLStreamException {
-        NormalizedNodeWriter normalizedNodeWriter = null;
-        NormalizedNodeStreamWriter normalizedNodeStreamWriter = null;
-        XMLStreamWriter writer = null;
-        try {
-            writer = XML_FACTORY.createXMLStreamWriter(result);
-            normalizedNodeStreamWriter = XMLStreamNormalizedNodeStreamWriter.create(writer, context, schemaPath);
-            normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(normalizedNodeStreamWriter);
-
-            normalizedNodeWriter.write(normalized);
-
-            normalizedNodeWriter.flush();
-        } finally {
-            try {
-                if(normalizedNodeWriter != null) {
-                    normalizedNodeWriter.close();
-                }
-                if(normalizedNodeStreamWriter != null) {
-                    normalizedNodeStreamWriter.close();
-                }
-                if(writer != null) {
-                    writer.close();
-                }
-            } catch (final Exception e) {
-                LOG.warn("Unable to close resource properly", e);
-            }
-        }
-    }
 }
index 5d1297322a846b74ae6b6977620cfff0cf6a075b..9b12a4166ec9c1bcdf9e8bb992242245fe0978b7 100644 (file)
@@ -7,8 +7,6 @@
  */
 
  /**
- * Utility classes for remote connectors e.g. netconf connector
- *
- * TODO extract into separate bundle when another connector is implemented e.g. restconf connector
+ * Utility classes for netconf connector
  */
 package org.opendaylight.netconf.sal.connect.util;
index c3befad9583311b7a6e4f7bd2820057e8a67cbf2..fa1e85ed1e25d0674ed8255b13e24d953323b4a7 100644 (file)
                             <shadedClassifierName>rest-perf-client</shadedClassifierName>
                         </configuration>
                     </execution>
+
+                    <execution>
+                        <id>scale-util</id>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <shadedArtifactId>scale-util</shadedArtifactId>
+                            <filters>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>META-INF/*.SF</exclude>
+                                        <exclude>META-INF/*.DSA</exclude>
+                                        <exclude>META-INF/*.RSA</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <transformers>
+                                <transformer
+                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <manifestEntries>
+                                        <Main-Class>org.opendaylight.netconf.test.tool.ScaleUtil</Main-Class>
+                                        <Class-Path>. lib lib/bcprov-jdk15on.jar lib/bcpkix-jdk15on.jar</Class-Path>
+                                    </manifestEntries>
+                                </transformer>
+                            </transformers>
+                            <shadedArtifactAttached>true</shadedArtifactAttached>
+                            <shadedClassifierName>scale-util</shadedClassifierName>
+                        </configuration>
+                    </execution>
                 </executions>
             </plugin>
             <plugin>
index 7f6595f614748193a9e9afedf13832c7ee8005af..1488b0545d954ff4cd6ca4f0ef64dea6336e32d6 100644 (file)
@@ -242,7 +242,7 @@ public final class Main {
         return null;
     }
 
-    private static class ConfigGenerator {
+    static class ConfigGenerator {
         public static final String NETCONF_CONNECTOR_XML = "/99-netconf-connector-simulated.xml";
         public static final String SIM_DEVICE_SUFFIX = "-sim-device";
 
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
new file mode 100644 (file)
index 0000000..6b5667c
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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;
+
+import ch.qos.logback.classic.Level;
+import com.google.common.base.Charsets;
+import com.google.common.base.Stopwatch;
+import com.google.common.io.CharStreams;
+import com.ning.http.client.AsyncHttpClient;
+import com.ning.http.client.AsyncHttpClientConfig.Builder;
+import com.ning.http.client.Request;
+import com.ning.http.client.Response;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.ConnectException;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+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.Main.Params;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ScaleUtil {
+
+    private static final Logger RESULTS_LOG = LoggerFactory.getLogger("results");
+    private static final ScheduledExecutorService executor = new LoggingWrapperExecutor(4);
+
+    private static final int deviceStep = 1000;
+    private static final long retryDelay = 10l;
+    private static final long timeout = 20l;
+
+    private static final Stopwatch stopwatch = Stopwatch.createUnstarted();
+
+    private static ScheduledFuture timeoutGuardFuture;
+    private static ch.qos.logback.classic.Logger root;
+    private static final Semaphore semaphore = new Semaphore(0);
+
+    public static void main(final String[] args) {
+        final Params params = parseArgs(args, Params.getParser());
+
+        root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+        root.setLevel(params.debug ? Level.DEBUG : Level.INFO);
+
+        // cleanup at the start in case controller was already running
+        final Runtime runtime = Runtime.getRuntime();
+        cleanup(runtime, params);
+
+        while (true) {
+            root.warn("Starting scale test with {} devices", params.deviceCount);
+            timeoutGuardFuture = executor.schedule(new TimeoutGuard(), timeout, TimeUnit.MINUTES);
+            final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator();
+            try {
+                final List<Integer> openDevices = netconfDeviceSimulator.start(params);
+                if (openDevices.size() == 0) {
+                    root.error("Failed to start any simulated devices, exiting...");
+                    System.exit(1);
+                }
+                if (params.distroFolder != null) {
+                    final Main.ConfigGenerator configGenerator = new Main.ConfigGenerator(params.distroFolder, openDevices);
+                    final List<File> generated = configGenerator.generate(
+                            params.ssh, params.generateConfigBatchSize,
+                            params.generateConfigsTimeout, params.generateConfigsAddress,
+                            params.devicesPerPort);
+                    configGenerator.updateFeatureFile(generated);
+                    configGenerator.changeLoadOrder();
+                }
+            } catch (final Exception e) {
+                root.error("Unhandled exception", e);
+                netconfDeviceSimulator.close();
+                System.exit(1);
+            }
+
+            root.warn(params.distroFolder.getAbsolutePath());
+            try {
+                runtime.exec(params.distroFolder.getAbsolutePath() + "/bin/start");
+                String status;
+                do {
+                    final Process exec = runtime.exec(params.distroFolder.getAbsolutePath() + "/bin/status");
+                    try {
+                        Thread.sleep(2000l);
+                    } catch (InterruptedException e) {
+                        root.warn("Failed to sleep", e);
+                    }
+                    status = CharStreams.toString(new BufferedReader(new InputStreamReader(exec.getInputStream())));
+                    root.warn("Current status: {}", status);
+                } while (!status.startsWith("Running ..."));
+                root.warn("Doing feature install {}", params.distroFolder.getAbsolutePath() + "/bin/client -u karaf feature:install odl-restconf-noauth odl-netconf-connector-all");
+                final Process featureInstall = runtime.exec(params.distroFolder.getAbsolutePath() + "/bin/client -u karaf feature:install odl-restconf-noauth odl-netconf-connector-all");
+                root.warn(CharStreams.toString(new BufferedReader(new InputStreamReader(featureInstall.getInputStream()))));
+                root.warn(CharStreams.toString(new BufferedReader(new InputStreamReader(featureInstall.getErrorStream()))));
+
+            } catch (IOException e) {
+                root.warn("Failed to start karaf", e);
+                System.exit(1);
+            }
+
+            root.warn("Karaf started, starting stopwatch");
+            stopwatch.start();
+
+            try {
+                executor.schedule(new ScaleVerifyCallable(netconfDeviceSimulator, params.deviceCount), retryDelay, TimeUnit.SECONDS);
+                root.warn("First callable scheduled");
+                semaphore.acquire();
+                root.warn("semaphore released");
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+
+            timeoutGuardFuture.cancel(false);
+            params.deviceCount += deviceStep;
+            netconfDeviceSimulator.close();
+            stopwatch.reset();
+
+            cleanup(runtime, params);
+        }
+    }
+
+    private static void cleanup(final Runtime runtime, final Params params) {
+        try {
+            stopKaraf(runtime, params);
+            deleteFolder(new File(params.distroFolder.getAbsoluteFile() + "/data"));
+
+        } catch (IOException | InterruptedException e) {
+            root.warn("Failed to stop karaf", e);
+            System.exit(1);
+        }
+    }
+
+    private static void stopKaraf(final Runtime runtime, final Params params) throws IOException, InterruptedException {
+        root.info("Stopping karaf and sleeping for 10 sec..");
+        String controllerPid = "";
+        do {
+
+            final Process pgrep = runtime.exec("pgrep -f org.apache.karaf.main.Main");
+
+            controllerPid = CharStreams.toString(new BufferedReader(new InputStreamReader(pgrep.getInputStream())));
+            root.warn(controllerPid);
+            runtime.exec("kill -9 " + controllerPid);
+
+            Thread.sleep(10000l);
+        } while (!controllerPid.isEmpty());
+        deleteFolder(new File(params.distroFolder.getAbsoluteFile() + "/data"));
+    }
+
+    private static void deleteFolder(File folder) {
+        File[] files = folder.listFiles();
+        if(files!=null) { //some JVMs return null for empty dirs
+            for(File f: files) {
+                if(f.isDirectory()) {
+                    deleteFolder(f);
+                } else {
+                    f.delete();
+                }
+            }
+        }
+        folder.delete();
+    }
+
+    private static Params parseArgs(final String[] args, final ArgumentParser parser) {
+        final Params parameters = new Params();
+        try {
+            parser.parseArgs(args, parameters);
+            return parameters;
+        } catch (ArgumentParserException e) {
+            parser.handleError(e);
+        }
+
+        System.exit(1);
+        return null;
+    }
+
+    private static class ScaleVerifyCallable implements Callable {
+
+        private static final Logger LOG = LoggerFactory.getLogger(ScaleVerifyCallable.class);
+
+        private static final String RESTCONF_URL = "http://127.0.0.1:8181/restconf/operational/network-topology:network-topology/topology/topology-netconf/";
+        private static final Pattern PATTERN = Pattern.compile("connected");
+
+        private final AsyncHttpClient asyncHttpClient = new AsyncHttpClient(new Builder()
+                .setConnectTimeout(Integer.MAX_VALUE)
+                .setRequestTimeout(Integer.MAX_VALUE)
+                .setAllowPoolingConnections(true)
+                .build());
+        private final NetconfDeviceSimulator simulator;
+        private final int deviceCount;
+        private final Request request;
+
+        public ScaleVerifyCallable(final NetconfDeviceSimulator simulator, final int deviceCount) {
+            LOG.info("New callable created");
+            this.simulator = simulator;
+            this.deviceCount = deviceCount;
+            AsyncHttpClient.BoundRequestBuilder requestBuilder = asyncHttpClient.prepareGet(RESTCONF_URL)
+                    .addHeader("content-type", "application/xml")
+                    .addHeader("Accept", "application/xml")
+                    .setRequestTimeout(Integer.MAX_VALUE);
+            request = requestBuilder.build();
+        }
+
+        @Override
+        public Object call() throws Exception {
+            try {
+                final Response response = asyncHttpClient.executeRequest(request).get();
+
+                if (response.getStatusCode() != 200 && response.getStatusCode() != 204) {
+                    LOG.warn("Request failed, status code: {}", response.getStatusCode() + response.getStatusText());
+                    executor.schedule(new ScaleVerifyCallable(simulator, deviceCount), retryDelay, TimeUnit.SECONDS);
+                } else {
+                    final String body = response.getResponseBody();
+                    final Matcher matcher = PATTERN.matcher(body);
+                    int count = 0;
+                    while (matcher.find()) {
+                        count++;
+                    }
+                    RESULTS_LOG.info("Currently connected devices : {} out of {}, time elapsed: {}", count, deviceCount + 1, stopwatch);
+                    if (count != deviceCount + 1) {
+                        executor.schedule(new ScaleVerifyCallable(simulator, deviceCount), retryDelay, TimeUnit.SECONDS);
+                    } else {
+                        stopwatch.stop();
+                        RESULTS_LOG.info("All devices connected in {}", stopwatch);
+                        semaphore.release();
+                    }
+                }
+            } catch (ConnectException | ExecutionException e) {
+                LOG.warn("Failed to connect to Restconf, is the controller running?", e);
+                executor.schedule(new ScaleVerifyCallable(simulator, deviceCount), retryDelay, TimeUnit.SECONDS);
+            }
+            return null;
+        }
+    }
+
+    private static class TimeoutGuard implements Callable {
+
+        @Override
+        public Object call() throws Exception {
+            RESULTS_LOG.warn("Timeout for scale test reached after: {} ..aborting", stopwatch);
+            root.warn("Timeout for scale test reached after: {} ..aborting", stopwatch);
+            System.exit(0);
+            return null;
+        }
+    }
+
+    public static class LoggingWrapperExecutor extends ScheduledThreadPoolExecutor {
+
+        public LoggingWrapperExecutor(int corePoolSize) {
+            super(corePoolSize);
+        }
+
+        @Override
+        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+            return super.schedule(wrapCallable(callable), delay, unit);
+        }
+
+        private Callable wrapCallable(Callable callable) {
+            return new LogOnExceptionCallable(callable);
+        }
+
+        private class LogOnExceptionCallable implements Callable {
+            private Callable theCallable;
+
+            public LogOnExceptionCallable(Callable theCallable) {
+                super();
+                this.theCallable = theCallable;
+            }
+
+            @Override
+            public Object call() throws Exception {
+                try {
+                    theCallable.call();
+                    return null;
+                } catch (Exception e) {
+                    // log
+                    root.warn("error in executing: " + theCallable + ". It will no longer be run!", e);
+
+                    // rethrow so that the executor can do it's thing
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+}
index 7985eef925204e3656fc75698cbaaf3081141dea..6f5736f0112b7cd67e3b24f0f18eeb848c1fab66 100644 (file)
@@ -53,6 +53,9 @@ public class Parameters {
     @Arg(dest = "auth")
     public ArrayList<String> auth;
 
+    @Arg(dest = "timeout")
+    public long timeout;
+
     static ArgumentParser getParser() {
         final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf stress client");
 
@@ -122,12 +125,19 @@ public class Parameters {
                 .help("Username and password for HTTP basic authentication in order username password.")
                 .dest("auth");
 
+        parser.addArgument("--timeout")
+                .type(Long.class)
+                .setDefault(5)
+                .help("Maximum time in minutes to wait for finishing all requests.")
+                .dest("timeout");
+
         return parser;
     }
 
     void validate() {
         Preconditions.checkArgument(port > 0, "Port =< 0");
         Preconditions.checkArgument(editCount > 0, "Edit count =< 0");
+        Preconditions.checkArgument(timeout > 0, "Timeout =< 0");
 
         Preconditions.checkArgument(editContent.exists(), "Edit content file missing");
         Preconditions.checkArgument(editContent.isDirectory() == false, "Edit content file is a dir");
index 270f6b0db94ecf7b54b5bde1c870da006eb7069b..5f6f490afc02069bfef37e9f61ae75433f0efc15 100644 (file)
@@ -20,7 +20,6 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 import net.sourceforge.argparse4j.inf.ArgumentParser;
 import net.sourceforge.argparse4j.inf.ArgumentParserException;
 import org.opendaylight.netconf.test.tool.TestToolUtils;
@@ -133,18 +132,23 @@ public class RestPerfClient {
         LOG.info("Starting performance test");
         final Stopwatch started = Stopwatch.createStarted();
         try {
-            final List<Future<Void>> futures = executorService.invokeAll(callables, 5, TimeUnit.MINUTES);
-            for (final Future<Void> future : futures) {
-                try {
-                    future.get(4L, TimeUnit.MINUTES);
-                } catch (ExecutionException | TimeoutException e) {
-                    throw new RuntimeException(e);
+            final List<Future<Void>> futures = executorService.invokeAll(callables, parameters.timeout, TimeUnit.MINUTES);
+            for (int i = 0; i < futures.size(); i++) {
+                Future<Void> future = futures.get(i);
+                if (future.isCancelled()) {
+                    LOG.info("{}. thread timed out.", i + 1);
+                } else {
+                    try {
+                        future.get();
+                    } catch (final ExecutionException e) {
+                        LOG.info("{}. thread failed.", i + 1, e);
+                    }
                 }
             }
-            executorService.shutdownNow();
         } catch (final InterruptedException e) {
-            throw new RuntimeException("Unable to execute requests", e);
+            LOG.warn("Unable to execute requests", e);
         }
+        executorService.shutdownNow();
         started.stop();
 
         LOG.info("FINISHED. Execution time: {}", started);
diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/scale/util/ScaleUtilParameters.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/scale/util/ScaleUtilParameters.java
new file mode 100644 (file)
index 0000000..1cc85ae
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.scale.util;
+
+import java.io.File;
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.annotation.Arg;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+
+public class ScaleUtilParameters {
+
+    @Arg(dest = "distro-folder")
+    public File distroFolder;
+
+    static ArgumentParser getParser() {
+        final ArgumentParser parser = ArgumentParsers.newArgumentParser("scale test helper");
+
+        parser.addArgument("--distribution-folder")
+                .type(File.class)
+                .help("Directory where the karaf distribution for controller is located")
+                .dest("distro-folder");
+
+        return parser;
+    }
+
+    static ScaleUtilParameters parseArgs(final String[] args, final ArgumentParser parser) {
+        final ScaleUtilParameters parameters = new ScaleUtilParameters();
+        try {
+            parser.parseArgs(args, parameters);
+            return parameters;
+        } catch (ArgumentParserException e) {
+            parser.handleError(e);
+        }
+
+        System.exit(1);
+        return null;
+    }
+
+}
index df3ab10f48c2145e47b053e2b5fd2cc4870346b7..1bdb2f02a0f0862d490ce7764b64bc8e0529651f 100644 (file)
         <appender-ref ref="STDOUT"/>
     </root>
 
+    <appender name="RESULTS-FILE" class="ch.qos.logback.core.FileAppender">
+        <file>scale-results.log</file>
+        <append>true</append>
+        <encoder>
+          <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="results" level="DEBUG" additivity="false">
+       <appender-ref ref="RESULTS-FILE"/>
+    </logger>
+
     <logger name="com.ning.http.client" level="WARN"/>
 </configuration>
\ No newline at end of file