Netconf active & passive component fix.
Change-Id: Ie7b533cef589fcbf16b9fc8b70184666c76f9588
diff --git a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java
index ac7735e..16c226d 100644
--- a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java
+++ b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfActiveComponent.java
@@ -33,8 +33,11 @@
import org.onosproject.netconf.client.NetconfTranslator;
import org.onosproject.netconf.client.NetconfTranslator.OperationType;
import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.InnerNode;
+import org.onosproject.yang.model.KeyLeaf;
import org.onosproject.yang.model.LeafNode;
import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
import org.onosproject.yang.model.ResourceId;
import org.onosproject.yang.runtime.DefaultResourceData;
import org.slf4j.Logger;
@@ -43,6 +46,11 @@
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.base.Preconditions.checkNotNull;
@Beta
@@ -63,10 +71,14 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetconfController controller;
+ public static final String DEVICES = "devices";
+ public static final String DEVICE = "device";
+ public static final String DEVICE_ID = "deviceid";
+
private ResourceId resId = new ResourceId.Builder()
- .addBranchPointSchema("device", DEVNMSPACE)
- .addBranchPointSchema("device", DEVNMSPACE)
- .addKeyLeaf("deviceid", DEVNMSPACE, "netconf:172.16.5.11:22")
+ .addBranchPointSchema(DEVICES, DEVNMSPACE)
+ .addBranchPointSchema(DEVICE, DEVNMSPACE)
+ .addKeyLeaf(DEVICE_ID, DEVNMSPACE, "netconf:172.16.5.11:22")
.build();
@Activate
@@ -83,7 +95,34 @@
@Override
public boolean isRelevant(DynamicConfigEvent event) {
- return event.subject().equals(resId);
+ return checkIfRelevant(event.subject());
+ }
+
+ /**
+ * Checks if this event is relevant for active component.
+ *
+ * @param id resource id
+ * @return true if relevant
+ */
+ private boolean checkIfRelevant(ResourceId id) {
+ checkNotNull(id, "resource id can't be null");
+ List<NodeKey> nodeKeys = id.nodeKeys();
+ if (nodeKeys != null && !nodeKeys.isEmpty() && nodeKeys.size() == 2) {
+ NodeKey key = nodeKeys.get(0);
+ if (key.schemaId().name().equals(DEVICES)) {
+ key = nodeKeys.get(1);
+ if (key.schemaId().name().equals(DEVICE)) {
+ ListKey listKey = (ListKey) key;
+ List<KeyLeaf> keyLeaves = listKey.keyLeafs();
+ if (keyLeaves != null && !keyLeaves.isEmpty()) {
+ return keyLeaves.get(0).leafSchema().name()
+ .equals(DEVICE_ID);
+ }
+ }
+ }
+ }
+ log.debug("not a relevant event for netconf active component");
+ return false;
}
public boolean isMaster(DeviceId deviceId) {
@@ -154,14 +193,21 @@
private boolean parseAndEdit(DataNode node, DeviceId deviceId,
ResourceId resourceId,
NetconfTranslator.OperationType operationType) {
+
+ //add all low level nodes of devices
+ Iterator<Map.Entry<NodeKey, DataNode>> it = ((InnerNode) node)
+ .childNodes().entrySet().iterator();
+ DefaultResourceData.Builder builder = DefaultResourceData.builder();
+ while (it.hasNext()) {
+ DataNode n = it.next().getValue();
+ if (!n.key().schemaId().name().equals("deviceid")) {
+ builder.addDataNode(n);
+ }
+ }
+ //add resouce id //TODO: check if it is correct
try {
return netconfTranslator.editDeviceConfig(
- deviceId,
- DefaultResourceData.builder()
- .addDataNode(node)
- .resourceId(resourceId)
- .build(),
- operationType);
+ deviceId, builder.build(), operationType);
} catch (IOException e) {
e.printStackTrace();
return false;
diff --git a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java
index 6e38729..b66a63e 100644
--- a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java
+++ b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/NetconfTranslatorImpl.java
@@ -16,42 +16,46 @@
package org.onosproject.netconf.client.impl;
+import com.google.common.annotations.Beta;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
import org.onosproject.cluster.NodeId;
import org.onosproject.net.DeviceId;
-import org.onosproject.netconf.client.NetconfTranslator;
import org.onosproject.netconf.NetconfController;
import org.onosproject.netconf.NetconfDevice;
+import org.onosproject.netconf.NetconfException;
import org.onosproject.netconf.NetconfSession;
-
-import org.onosproject.yang.model.ResourceData;
+import org.onosproject.netconf.client.NetconfTranslator;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.InnerNode;
import org.onosproject.yang.model.KeyLeaf;
-import org.onosproject.yang.model.ListKey;
import org.onosproject.yang.model.LeafListKey;
+import org.onosproject.yang.model.LeafNode;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceData;
+import org.onosproject.yang.model.ResourceId;
import org.onosproject.yang.model.SchemaContext;
import org.onosproject.yang.model.SchemaContextProvider;
import org.onosproject.yang.model.SchemaId;
-import org.onosproject.yang.model.DataNode;
-import org.onosproject.yang.model.NodeKey;
-import org.onosproject.yang.model.ResourceId;
-import org.onosproject.yang.model.InnerNode;
-import org.onosproject.yang.model.LeafNode;
-
-import org.onosproject.yang.runtime.DefaultCompositeData;
-import org.onosproject.yang.runtime.DefaultRuntimeContext;
-import org.onosproject.yang.runtime.YangRuntimeService;
-import org.onosproject.yang.runtime.DefaultCompositeStream;
import org.onosproject.yang.runtime.CompositeStream;
import org.onosproject.yang.runtime.DefaultAnnotatedNodeInfo;
import org.onosproject.yang.runtime.DefaultAnnotation;
+import org.onosproject.yang.runtime.DefaultCompositeData;
+import org.onosproject.yang.runtime.DefaultCompositeStream;
import org.onosproject.yang.runtime.DefaultResourceData;
-import org.onosproject.yang.runtime.YangSerializerContext;
+import org.onosproject.yang.runtime.DefaultRuntimeContext;
import org.onosproject.yang.runtime.DefaultYangSerializerContext;
-/*FIXME these imports are not visible using OSGI*/
+import org.onosproject.yang.runtime.YangRuntimeService;
+import org.onosproject.yang.runtime.YangSerializerContext;
import org.onosproject.yang.runtime.helperutils.SerializerHelper;
-
-import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
-import static org.onosproject.yang.runtime.helperutils.SerializerHelper.addDataNode;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
@@ -59,32 +63,26 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.List;
-import java.util.Iterator;
-
-import com.google.common.annotations.Beta;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-
-import org.osgi.service.component.ComponentContext;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
+import static org.onosproject.yang.runtime.helperutils.SerializerHelper.addDataNode;
+
+/*FIXME these imports are not visible using OSGI*/
+
+/*FIXME these imports are not visible using OSGI*/
/*TODO once the API's are finalized this comment will be made more specified.*/
+
/**
* Translator which accepts data types defined for the DynamicConfigService and
* makes the appropriate calls to NETCONF devices before encoding and returning
* responses in formats suitable for the DynamicConfigService.
- *
+ * <p>
* NOTE: This entity does not ensure you are the master of a device you attempt
* to contact. If you are not the master an error will be thrown because there
* will be no session available.
@@ -114,7 +112,7 @@
private static final String GET_URI = "urn:ietf:params:xml:ns:yang:" +
"yrt-ietf-network:networks/network/node";
- private static final String XML_ENCODING_SPECIFIER = "XML";
+ private static final String XML_ENCODING_SPECIFIER = "xml";
private static final String OP_SPECIFIER = "xc:operation";
private static final String REPLACE_OP_SPECIFIER = "replace";
private static final String DELETE_OP_SPECIFIER = "delete";
@@ -167,40 +165,46 @@
SchemaContext context = schemaContextProvider
.getSchemaContext(ResourceId.builder().addBranchPointSchema("/", null).build());
ResourceData modifiedPathResourceData = getResourceData(resourceData.resourceId(),
- resourceData.dataNodes(),
- new DefaultYangSerializerContext(context, null));
+ resourceData.dataNodes(),
+ new DefaultYangSerializerContext(context, null));
DefaultCompositeData.Builder compositeDataBuilder = DefaultCompositeData
.builder()
.resourceData(modifiedPathResourceData);
for (DataNode node : resourceData.dataNodes()) {
ResourceId resourceId = resourceData.resourceId();
if (operationType != OperationType.DELETE) {
- resourceId = getAnnotatedNodeResourceId(resourceData.resourceId(), node);
+ resourceId = getAnnotatedNodeResourceId(
+ resourceData.resourceId(), node);
}
if (resourceId != null) {
- DefaultAnnotatedNodeInfo.Builder annotatedNodeInfo = DefaultAnnotatedNodeInfo.builder();
+ DefaultAnnotatedNodeInfo.Builder annotatedNodeInfo =
+ DefaultAnnotatedNodeInfo.builder();
annotatedNodeInfo.resourceId(resourceId);
- annotatedNodeInfo.addAnnotation(new DefaultAnnotation(OP_SPECIFIER,
- operationType == OperationType.DELETE ?
- DELETE_OP_SPECIFIER : REPLACE_OP_SPECIFIER));
+ annotatedNodeInfo.addAnnotation(
+ new DefaultAnnotation(
+ OP_SPECIFIER, operationType == OperationType.DELETE ?
+ DELETE_OP_SPECIFIER : REPLACE_OP_SPECIFIER));
compositeDataBuilder.addAnnotatedNodeInfo(annotatedNodeInfo.build());
}
}
- CompositeStream config = yangRuntimeService.encode(compositeDataBuilder.build(),
- new DefaultRuntimeContext.Builder()
- .setDataFormat(XML_ENCODING_SPECIFIER)
- .addAnnotation(
- new DefaultAnnotation(
- XMLNS_XC_SPECIFIER,
- NETCONF_1_0_BASE_NAMESPACE))
- .build());
+ CompositeStream config = yangRuntimeService.encode(
+ compositeDataBuilder.build(),
+ new DefaultRuntimeContext.Builder()
+ .setDataFormat(XML_ENCODING_SPECIFIER)
+ .addAnnotation(new DefaultAnnotation(
+ XMLNS_XC_SPECIFIER, NETCONF_1_0_BASE_NAMESPACE))
+ .build());
/* FIXME need to fix to string conversion. */
- if (session.editConfig(streamToString(config.resourceData()))) {
- /* NOTE: a failure to edit is reflected as a NetconfException.*/
- return true;
+
+ try {
+ String reply = session.requestSync(Utils.editConfig(streamToString(
+ config.resourceData())));
+ } catch (NetconfException e) {
+ log.error("failed to send a request sync", e);
+ return false;
}
- log.warn("Editing of the netconf device: {} failed.", deviceId);
- return false;
+ /* NOTE: a failure to edit is reflected as a NetconfException.*/
+ return true;
}
@Override
@@ -210,23 +214,25 @@
String reply = session.get(null, null);
Matcher protocolStripper = GET_CORE_MESSAGE_PATTERN.matcher(reply);
reply = protocolStripper.group(GET_CORE_MESSAGE_GROUP);
- return yangRuntimeService.decode(new DefaultCompositeStream(
- null,
+ return yangRuntimeService.decode(
+ new DefaultCompositeStream(
+ null,
/*FIXME is UTF_8 the appropriate encoding? */
- new ByteArrayInputStream(reply.toString().getBytes(StandardCharsets.UTF_8))),
- new DefaultRuntimeContext.Builder()
- .setDataFormat(XML_ENCODING_SPECIFIER)
- .addAnnotation(
- new DefaultAnnotation(
- XMLNS_SPECIFIER,
- NETCONF_1_0_BASE_NAMESPACE))
- .build()).resourceData();
+ new ByteArrayInputStream(reply.getBytes(StandardCharsets.UTF_8))),
+ new DefaultRuntimeContext.Builder()
+ .setDataFormat(XML_ENCODING_SPECIFIER)
+ .addAnnotation(
+ new DefaultAnnotation(
+ XMLNS_SPECIFIER,
+ NETCONF_1_0_BASE_NAMESPACE))
+ .build()).resourceData();
/* NOTE: a failure to get is reflected as a NetconfException.*/
}
/**
* Returns a session for the specified deviceId if this node is its master,
* returns null otherwise.
+ *
* @param deviceId the id of node for witch we wish to retrieve a session
* @return a NetconfSession with the specified node or null
*/
@@ -261,7 +267,7 @@
* Returns resource data having resource id as "/" and data node tree
* starting from "/" by creating data nodes for given resource id(parent
* node for given list of nodes) and list of child nodes.
- *
+ * <p>
* This api will be used in encode flow only.
*
* @param rid resource identifier till parent node
@@ -271,14 +277,18 @@
*/
public static ResourceData getResourceData(
ResourceId rid, List<DataNode> nodes, YangSerializerContext cont) {
+ if (rid == null) {
+ ResourceData.Builder resData = DefaultResourceData.builder();
+ for (DataNode node : nodes) {
+ resData.addDataNode(node);
+ }
+ return resData.build();
+ }
List<NodeKey> keys = rid.nodeKeys();
Iterator<NodeKey> it = keys.iterator();
DataNode.Builder dbr = SerializerHelper.initializeDataNode(cont);
// checking the resource id weather it is getting started from / or not
- if (it.next().schemaId().name() != "/") {
- //exception
- }
while (it.hasNext()) {
NodeKey nodekey = it.next();
@@ -322,15 +332,16 @@
resData.resourceId(null);
return resData.build();
}
+
/**
* Returns resource id for annotated data node by adding resource id of top
* level data node to given resource id.
- *
+ * <p>
* Annotation will be added to node based on the updated resource id.
* This api will be used in encode flow only.
*
- * @param rid resource identifier till parent node
- * @param node data node
+ * @param rid resource identifier till parent node
+ * @param node data node
* @return updated resource id.
*/
public static ResourceId getAnnotatedNodeResourceId(ResourceId rid,
@@ -338,10 +349,14 @@
String val;
ResourceId.Builder rIdBldr = ResourceId.builder();
- try {
- rIdBldr = rid.copyBuilder();
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
+ if (rid != null) {
+ try {
+ rIdBldr = rid.copyBuilder();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ rIdBldr.addBranchPointSchema("/", null);
}
DataNode.Type type = node.type();
NodeKey k = node.key();
diff --git a/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/Utils.java b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/Utils.java
new file mode 100644
index 0000000..96a1ecc
--- /dev/null
+++ b/apps/netconf/client/src/main/java/org/onosproject/netconf/client/impl/Utils.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.netconf.client.impl;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+/**
+ * Represents utilities for huawei driver.
+ */
+public final class Utils {
+
+ /**
+ * Prevents creation of utils instance.
+ */
+ private Utils() {
+ }
+
+ // Default namespace given in yang files
+ private static final String XMLNS_STRING = "xmlns=\"ne-l3vpn-api\"";
+ private static final String XMLNS_HUA_STRING = "xmlns=\"http://www.huawei" +
+ ".com/netconf/vrp\" format-version=\"1.0\" content-version=\"1.0\"";
+
+ /**
+ * YMS encode the java object into a xml string with xml namespace equals to
+ * the namespace defined in YANG file. Huawei driver overwriting this
+ * default xml namespace in generated xml string with xml string for Huawei.
+ *
+ * @param request xml string as an output of YMS encode operation
+ * @return formatted string
+ */
+ private static String formatMessage(String request) {
+ if (request.contains(XMLNS_STRING)) {
+ request = request.replaceFirst(XMLNS_STRING, XMLNS_HUA_STRING);
+ }
+ return request;
+ }
+
+ /**
+ * Returns the appended provided xml string with device specific rpc
+ * request tags.
+ *
+ * @param encodedString xml string need to be updated
+ * @return appended new tags xml string
+ */
+ static String editConfig(String encodedString) {
+
+ // Add opening protocol edit config tags.
+ StringBuilder rpc =
+ new StringBuilder(
+ "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0" +
+ "\" " +
+ "message-id=\"1\">");
+ rpc.append("<edit-config>");
+ rpc.append("<target>");
+ rpc.append("<running/>");
+ rpc.append("</target>");
+
+ // Get the formatted XML namespace string.
+ encodedString = formatMessage(encodedString);
+
+ // Add the closing protocol edit config tags.
+ rpc.append(encodedString);
+ rpc.append("</edit-config>");
+ rpc.append("</rpc>");
+
+ return rpc.toString();
+ }
+
+ /**
+ * Converts xml string to pretty format.
+ *
+ * @param input xml string to be converted to pretty format
+ * @return pretty format xml string
+ */
+ static String prettyFormat(String input) {
+ // Prepare input and output stream
+ Source xmlInput = new StreamSource(new StringReader(input));
+ StringWriter stringWriter = new StringWriter();
+ StreamResult xmlOutput = new StreamResult(stringWriter);
+
+ // Create transformer
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = null;
+
+ try {
+ transformer = transformerFactory.newTransformer();
+ } catch (TransformerConfigurationException e) {
+ e.printStackTrace();
+ }
+
+ // Need to omit the xml header and set indent to 4
+ if (transformer != null) {
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache" +
+ ".org/xslt}indent-amount", "4");
+
+ // Covert input string to xml pretty format and return
+ try {
+ transformer.transform(xmlInput, xmlOutput);
+ } catch (TransformerException e) {
+ e.printStackTrace();
+ }
+ }
+ return xmlOutput.getWriter().toString();
+ }
+}