BUG-8085: create missing parent augmentation node 12/58312/1
authorMarek Gradzki <mgradzki@cisco.com>
Mon, 5 Jun 2017 14:28:44 +0000 (16:28 +0200)
committerMarek Gradzki <mgradzki@cisco.com>
Tue, 6 Jun 2017 08:49:04 +0000 (10:49 +0200)
Augmentation nodes do not exist in serialized form
(e.g. in edit-config message), but are required by DataTree-based
DOMDataBroker implementations, so should be created if data from
augment is present.

This patch creates missing augment nodes by issuing merge on augmentation
before put operation (based on current behaviour for ListSchemaNodes).

Change-Id: If657ae96e914fc46617099042a833c7d4d5883b7
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/EditConfig.java
netconf/mdsal-netconf-connector/src/test/java/org/opendaylight/netconf/mdsal/connector/ops/NetconfMDSalMappingTest.java
netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_augmented_container_replace.xml [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_empty_modules_create.xml [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_leaf_from_augment_replace.xml [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/test/resources/yang/mdsal-netconf-mapping-test.yang

index e3bb3cd1000c662ee57b42423f9e899a7584eb63..563fc2e27c7fb68721bb556ecaee770ab5fdd954 100644 (file)
@@ -36,6 +36,7 @@ import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -121,7 +122,7 @@ public class EditConfig extends AbstractSingletonNetconfOperation {
         case NONE:
             return;
         case MERGE:
-            mergeParentMap(rwtx, path, changeData);
+            mergeParentMixin(rwtx, path, changeData);
             rwtx.merge(LogicalDatastoreType.CONFIGURATION, path, changeData);
             break;
         case CREATE:
@@ -131,14 +132,14 @@ public class EditConfig extends AbstractSingletonNetconfOperation {
                     throw new DocumentedException("Data already exists, cannot execute CREATE operation",
                         ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, ErrorSeverity.ERROR);
                 }
-                mergeParentMap(rwtx, path, changeData);
+                mergeParentMixin(rwtx, path, changeData);
                 rwtx.put(LogicalDatastoreType.CONFIGURATION, path, changeData);
             } catch (final ReadFailedException e) {
                 LOG.warn("Read from datastore failed when trying to read data for create operation", change, e);
             }
             break;
         case REPLACE:
-            mergeParentMap(rwtx, path, changeData);
+            mergeParentMixin(rwtx, path, changeData);
             rwtx.put(LogicalDatastoreType.CONFIGURATION, path, changeData);
             break;
         case DELETE:
@@ -161,14 +162,13 @@ public class EditConfig extends AbstractSingletonNetconfOperation {
         }
     }
 
-    private void mergeParentMap(final DOMDataReadWriteTransaction rwtx, final YangInstanceIdentifier path,
-                                final NormalizedNode<?, ?> change) {
+    private void mergeParentMixin(final DOMDataReadWriteTransaction rwtx, final YangInstanceIdentifier path,
+                                final NormalizedNode change) {
+        final YangInstanceIdentifier parentNodeYid = path.getParent();
         if (change instanceof MapEntryNode) {
-            final YangInstanceIdentifier mapNodeYid = path.getParent();
-
             final SchemaNode schemaNode = SchemaContextUtil.findNodeInSchemaContext(
                     schemaContext.getCurrentContext(),
-                    mapNodeYid.getPathArguments().stream()
+                    parentNodeYid.getPathArguments().stream()
                             // filter out identifiers not present in the schema tree
                             .filter(arg -> !(arg instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates))
                             .filter(arg -> !(arg instanceof YangInstanceIdentifier.AugmentationIdentifier))
@@ -180,16 +180,23 @@ public class EditConfig extends AbstractSingletonNetconfOperation {
             //merge empty ordered or unordered map
             if (((ListSchemaNode) schemaNode).isUserOrdered()) {
                 final MapNode mixinNode = Builders.orderedMapBuilder()
-                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(mapNodeYid.getLastPathArgument().getNodeType()))
+                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(parentNodeYid.getLastPathArgument().getNodeType()))
                         .build();
-                rwtx.merge(LogicalDatastoreType.CONFIGURATION, mapNodeYid, mixinNode);
+                rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, mixinNode);
                 return;
             }
 
             final MapNode mixinNode = Builders.mapBuilder()
-                    .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(mapNodeYid.getLastPathArgument().getNodeType()))
+                    .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(parentNodeYid.getLastPathArgument().getNodeType()))
                     .build();
-            rwtx.merge(LogicalDatastoreType.CONFIGURATION, mapNodeYid, mixinNode);
+            rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, mixinNode);
+        } else if (parentNodeYid.getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) {
+            // merge empty augmentation node
+            final YangInstanceIdentifier.AugmentationIdentifier augmentationYid =
+                (YangInstanceIdentifier.AugmentationIdentifier) parentNodeYid.getLastPathArgument();
+            final AugmentationNode augmentationNode = Builders.augmentationBuilder()
+                .withNodeIdentifier(augmentationYid).build();
+            rwtx.merge(LogicalDatastoreType.CONFIGURATION, parentNodeYid, augmentationNode);
         }
     }
 
index 2d5e971dc333595e60db3ff1b0c26f839c17729f..7fe00acd36ecbb085ce026996c22fc6aefc1234e 100644 (file)
@@ -327,6 +327,32 @@ public class NetconfMDSalMappingTest {
 
     }
 
+    @Test
+    public void testAugmentedContainerReplace() throws Exception {
+        verifyResponse(edit("messages/mapping/editConfigs/editConfig_empty_modules_create.xml"),
+            RPC_REPLY_OK);
+        verifyResponse(commit(), RPC_REPLY_OK);
+
+        verifyResponse(edit("messages/mapping/editConfigs/editConfig_augmented_container_replace.xml"),
+            RPC_REPLY_OK);
+        verifyResponse(commit(), RPC_REPLY_OK);
+
+        deleteDatastore();
+    }
+
+    @Test
+    public void testLeafFromAugmentReplace() throws Exception {
+        verifyResponse(edit("messages/mapping/editConfigs/editConfig_empty_modules_create.xml"),
+            RPC_REPLY_OK);
+        verifyResponse(commit(), RPC_REPLY_OK);
+
+        verifyResponse(edit("messages/mapping/editConfigs/editConfig_leaf_from_augment_replace.xml"),
+            RPC_REPLY_OK);
+        verifyResponse(commit(), RPC_REPLY_OK);
+
+        deleteDatastore();
+    }
+
     @Test
     public void testLock() throws Exception {
 
diff --git a/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_augmented_container_replace.xml b/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_augmented_container_replace.xml
new file mode 100644 (file)
index 0000000..184b3a0
--- /dev/null
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (c) 2017 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
+  -->
+
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <candidate/>
+        </target>
+        <test-option>
+            set
+        </test-option>
+        <default-operation>none</default-operation>
+        <config>
+            <top xmlns="urn:opendaylight:mdsal:mapping:test">
+                <modules>
+                    <augmented-container xmlns:a="urn:ietf:params:xml:ns:netconf:base:1.0" a:operation="replace">
+                        <identifier>some id</identifier>
+                    </augmented-container>
+                </modules>
+            </top>
+        </config>
+    </edit-config>
+</rpc>
\ No newline at end of file
diff --git a/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_empty_modules_create.xml b/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_empty_modules_create.xml
new file mode 100644 (file)
index 0000000..7478bfd
--- /dev/null
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (c) 2017 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
+  -->
+
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <candidate/>
+        </target>
+        <test-option>
+            set
+        </test-option>
+        <default-operation>none</default-operation>
+        <config>
+            <top xmlns="urn:opendaylight:mdsal:mapping:test" xmlns:a="urn:ietf:params:xml:ns:netconf:base:1.0" a:operation="create">
+                <modules>
+                </modules>
+            </top>
+        </config>
+    </edit-config>
+</rpc>
\ No newline at end of file
diff --git a/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_leaf_from_augment_replace.xml b/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/editConfigs/editConfig_leaf_from_augment_replace.xml
new file mode 100644 (file)
index 0000000..3f82522
--- /dev/null
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (c) 2017 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
+  -->
+
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <edit-config>
+        <target>
+            <candidate/>
+        </target>
+        <test-option>
+            set
+        </test-option>
+        <default-operation>none</default-operation>
+        <config>
+            <top xmlns="urn:opendaylight:mdsal:mapping:test">
+                <modules>
+                    <leaf-from-augment xmlns:a="urn:ietf:params:xml:ns:netconf:base:1.0" a:operation="replace">some value</leaf-from-augment>
+                </modules>
+            </top>
+        </config>
+    </edit-config>
+</rpc>
\ No newline at end of file
index bf363b321b360cb82373dbdc5c57d893024d5c58..2557dbcc86f33bee9a16315ea43c228d950cd778 100644 (file)
@@ -181,13 +181,19 @@ module config {
     }
 
     augment "/map:top/map:modules/" {
-        container augmented-container{
+        container augmented-container {
             leaf identifier {
                 type string;
             }
         }
     }
 
+    augment "/map:top/map:modules/" {
+        leaf leaf-from-augment {
+            type string;
+        }
+    }
+
     augment "/map:top" {
         container mid-level {
             container low-level {