BUG-8085: create missing parent augmentation node 66/58266/3
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:32:38 +0000 (10:32 +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 390c1d63c947770878f71ebd0850b49252644ef8..9e13ff9d900dd82646d86b3a4b2068d8acb67ef3 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;
@@ -118,7 +119,7 @@ public class EditConfig extends AbstractSingletonNetconfOperation {
             return;
         case MERGE:
             rwtx.merge(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(change.getPath()), change.getChangeRoot());
-            mergeParentMap(rwtx, path, changeData);
+            mergeParentMixin(rwtx, path, changeData);
             break;
         case CREATE:
             try {
@@ -126,14 +127,14 @@ public class EditConfig extends AbstractSingletonNetconfOperation {
                 if (readResult.isPresent()) {
                     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:
@@ -155,14 +156,13 @@ public class EditConfig extends AbstractSingletonNetconfOperation {
         }
     }
 
-    private void mergeParentMap(final DOMDataReadWriteTransaction rwtx, final YangInstanceIdentifier path,
+    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))
@@ -174,16 +174,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 7a375d9c7bb244d16e49c8444c166f87762d0d42..7923b090db96de28ed30a64c698154bf7bd64395 100644 (file)
@@ -329,6 +329,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 {