From: Maros Marsalek Date: Thu, 17 Mar 2016 10:12:19 +0000 (+0000) Subject: Merge "Avoid relying on the timezone" X-Git-Tag: release/boron~173 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=e8cf3b81e68425017d389a69f852a336b40b8605;hp=16c5cc77e4942b3cf73d379fe9dd8fb40663aeaa;p=netconf.git Merge "Avoid relying on the timezone" --- diff --git a/netconf/abstract-topology/pom.xml b/netconf/abstract-topology/pom.xml index 827e4de1b7..b6d7509537 100644 --- a/netconf/abstract-topology/pom.xml +++ b/netconf/abstract-topology/pom.xml @@ -29,10 +29,6 @@ - - 2.3.14 - 2.11 - 7 @@ -59,27 +55,22 @@ org.scala-lang scala-library - ${scala.major.version}.${scala.minor.version} com.typesafe.akka - akka-actor_${scala.major.version} - ${akka.version} + akka-actor_${scala.version} com.typesafe.akka - akka-remote_${scala.major.version} - ${akka.version} + akka-remote_${scala.version} com.typesafe.akka - akka-cluster_${scala.major.version} - ${akka.version} + akka-cluster_${scala.version} com.typesafe.akka - akka-osgi_${scala.major.version} - ${akka.version} + akka-osgi_${scala.version} com.typesafe diff --git a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java index 33cde89cd9..4f0a53a43c 100644 --- a/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java +++ b/netconf/abstract-topology/src/main/java/org/opendaylight/netconf/topology/util/SalNodeWriter.java @@ -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"); } diff --git a/netconf/messagebus-netconf/src/main/java/org/opendaylight/netconf/messagebus/eventsources/netconf/NetconfEventSource.java b/netconf/messagebus-netconf/src/main/java/org/opendaylight/netconf/messagebus/eventsources/netconf/NetconfEventSource.java index a085088571..28300753b3 100644 --- a/netconf/messagebus-netconf/src/main/java/org/opendaylight/netconf/messagebus/eventsources/netconf/NetconfEventSource.java +++ b/netconf/messagebus-netconf/src/main/java/org/opendaylight/netconf/messagebus/eventsources/netconf/NetconfEventSource.java @@ -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); diff --git a/netconf/netconf-impl/src/main/java/org/opendaylight/netconf/impl/NetconfServerSessionListener.java b/netconf/netconf-impl/src/main/java/org/opendaylight/netconf/impl/NetconfServerSessionListener.java index ae0a07f4ef..a1a16f426c 100644 --- a/netconf/netconf-impl/src/main/java/org/opendaylight/netconf/impl/NetconfServerSessionListener.java +++ b/netconf/netconf-impl/src/main/java/org/opendaylight/netconf/impl/NetconfServerSessionListener.java @@ -125,8 +125,7 @@ public class NetconfServerSessionListener implements NetconfSessionListener : 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())); diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java index c8d4b90f39..6219f91b2d 100644 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java +++ b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java @@ -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; diff --git a/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/Get.java b/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/Get.java index 9ed609da5b..78db2f6c69 100644 --- a/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/Get.java +++ b/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/Get.java @@ -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); } diff --git a/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/NotificationsTransformUtil.java b/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/NotificationsTransformUtil.java index 0aff22803c..0ac4849203 100644 --- a/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/NotificationsTransformUtil.java +++ b/netconf/netconf-notifications-impl/src/main/java/org/opendaylight/netconf/notifications/impl/ops/NotificationsTransformUtil.java @@ -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); - } - } - } - } diff --git a/netconf/netconf-topology/src/test/resources/test.conf b/netconf/netconf-topology/src/test/resources/test.conf index 3346d64ad8..b8c72947b5 100644 --- a/netconf/netconf-topology/src/test/resources/test.conf +++ b/netconf/netconf-topology/src/test/resources/test.conf @@ -1,7 +1,5 @@ akka { - version = "2.3.14" - actor { provider = "akka.cluster.ClusterActorRefProvider" @@ -21,5 +19,4 @@ akka { hostname = "127.0.0.1" } } - } diff --git a/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/NetconfUtil.java b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/NetconfUtil.java index 9b47c58e57..0e8b9aeec4 100644 --- a/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/NetconfUtil.java +++ b/netconf/netconf-util/src/main/java/org/opendaylight/netconf/util/NetconfUtil.java @@ -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); + } + } + } } diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/package-info.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/package-info.java index ddc3e4a2bf..399cdf0f3b 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/package-info.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/package-info.java @@ -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; diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java index 6cb51966ba..68805c40d4 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceNotificationService.java @@ -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() { @Override public void close() { diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java index f5ebbbbe50..668415aa6b 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/schema/mapping/NetconfMessageTransformer.java @@ -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 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); - } - } - } } diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/package-info.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/package-info.java index 5d1297322a..9b12a4166e 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/package-info.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/package-info.java @@ -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; diff --git a/netconf/tools/netconf-testtool/pom.xml b/netconf/tools/netconf-testtool/pom.xml index c3befad958..fa1e85ed1e 100644 --- a/netconf/tools/netconf-testtool/pom.xml +++ b/netconf/tools/netconf-testtool/pom.xml @@ -307,6 +307,38 @@ rest-perf-client + + + scale-util + + shade + + package + + scale-util + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + org.opendaylight.netconf.test.tool.ScaleUtil + . lib lib/bcprov-jdk15on.jar lib/bcpkix-jdk15on.jar + + + + true + scale-util + + 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 7f6595f614..1488b0545d 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 @@ -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 index 0000000000..6b5667c932 --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/ScaleUtil.java @@ -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 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 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 ScheduledFuture schedule(Callable 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); + } + } + } + } +} diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/Parameters.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/Parameters.java index 7985eef925..6f5736f011 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/Parameters.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/Parameters.java @@ -53,6 +53,9 @@ public class Parameters { @Arg(dest = "auth") public ArrayList 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"); diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RestPerfClient.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RestPerfClient.java index 270f6b0db9..5f6f490afc 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RestPerfClient.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RestPerfClient.java @@ -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> futures = executorService.invokeAll(callables, 5, TimeUnit.MINUTES); - for (final Future future : futures) { - try { - future.get(4L, TimeUnit.MINUTES); - } catch (ExecutionException | TimeoutException e) { - throw new RuntimeException(e); + final List> futures = executorService.invokeAll(callables, parameters.timeout, TimeUnit.MINUTES); + for (int i = 0; i < futures.size(); i++) { + Future 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 index 0000000000..1cc85ae216 --- /dev/null +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/scale/util/ScaleUtilParameters.java @@ -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; + } + +} diff --git a/netconf/tools/netconf-testtool/src/main/resources/logback.xml b/netconf/tools/netconf-testtool/src/main/resources/logback.xml index df3ab10f48..1bdb2f02a0 100644 --- a/netconf/tools/netconf-testtool/src/main/resources/logback.xml +++ b/netconf/tools/netconf-testtool/src/main/resources/logback.xml @@ -18,5 +18,17 @@ + + scale-results.log + true + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file