[NETCONF-486] Patch request on a Netconf Mounted device throwing ClassCastException from YANG tools Created: 17/Nov/17  Updated: 28/May/18  Resolved: 28/May/18

Status: Resolved
Project: netconf
Component/s: netconf
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: High
Reporter: Balaji Varadaraju Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Tested on Carbon stable, Oxygen and Nitrogen. All exhibit the similar behavior and call fails. The stack trace attached is for Carbon SR1.



 Description   

We are seeing a issue with the HTTP PATCH request on a particular model on the NETCONF mounted resource. PATCH request works fine on certain models hosted inside ODL. But this issue is related to a model on a NETCONF mounted device.

Here are the steps we did. We made sure PUT call works.

Request Type : PUT

URL : http://controller:port/restconf/config/network-topology:network-topology/topology/topology-netconf/node/node/yang-ext:mount/exa-base:config/profile/dhcp-v4-server-profile/dhcp-profile-name/

Payload :

{
"dhcp-v4-server-profile":
{
"name": "dhcp-profile-name",
"pool": [
"dhcp-pool-name"
]
}

}

PUT call works.

We wanted to use the PATCH request to manipulate the leaf-list. In the above request "pool" is a leaf-list.

We tried this PATCH request

Request Type : PATCH

URL : http://controller:port/restconf/config/network-topology:network-topology/topology/topology-netconf/node/node/yang-ext:mount/exa-base:config/profile/dhcp-v4-server-profile/dhcp-profile-name/

Payload :

{
"ietf-restconf:yang-patch" :
{
"patch-id" : "0",
"edit" :
[
{
"edit-id" : "edit1",
"operation" : "merge",
"target" : "",
"value" :
{
"dhcp-v4-server-profile":

{ "name": "profile1", "pool": [ "pool1" ] }

}
}
]
}
}

The request itself returns success in restconf and we obtain this output.

{
"ietf-yang-patch:yang-patch-status":

{ "patch-id": "0", "ok": [ null ] }

}

However we don't see the desired result and we see the ClassCastException by YANG tools in the karaf.log.

17-11-13 03:03:16,519 | ERROR | ult-dispatcher-3 | OneForOneStrategy | 180 - com.typesafe.akka.slf4j - 2.4.18 | org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder$ImmutableMapNode cannot be cast to org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode
java.lang.ClassCastException: org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder$ImmutableMapNode cannot be cast to org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode
at org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder.withValue(ImmutableMapNodeBuilder.java:81)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder.withValue(ImmutableMapNodeBuilder.java:28)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:104)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:101)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:101)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:101)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.yangtools.yang.data.impl.schema.InstanceIdToCompositeNodes.create(InstanceIdToCompositeNodes.java:101)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.fromInstanceId(ImmutableNodes.java:136)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.createEditConfigAnyxml(NetconfMessageTransformUtil.java:294)[300:org.opendaylight.netconf.sal-netconf-connector:1.5.1.Carbon]
at org.opendaylight.netconf.sal.connect.netconf.util.NetconfRpcStructureTransformer.createEditConfigStructure(NetconfRpcStructureTransformer.java:39)[300:org.opendaylight.netconf.sal-netconf-connector:1.5.1.Carbon]
at org.opendaylight.netconf.sal.connect.netconf.util.NetconfBaseOps.createEditConfigStrcture(NetconfBaseOps.java:261)[300:org.opendaylight.netconf.sal-netconf-connector:1.5.1.Carbon]
at org.opendaylight.netconf.sal.connect.netconf.sal.tx.AbstractWriteTx.merge(AbstractWriteTx.java:117)[300:org.opendaylight.netconf.sal-netconf-connector:1.5.1.Carbon]
at org.opendaylight.netconf.sal.connect.netconf.sal.tx.ReadWriteTx.merge(ReadWriteTx.java:47)[300:org.opendaylight.netconf.sal-netconf-connector:1.5.1.Carbon]
at org.opendaylight.netconf.topology.singleton.impl.actors.WriteAdapter.handle(WriteAdapter.java:60)[303:org.opendaylight.netconf.topology-singleton:1.2.1.Carbon]
at org.opendaylight.netconf.topology.singleton.impl.actors.ReadWriteTransactionActor.onReceive(ReadWriteTransactionActor.java:56)[303:org.opendaylight.netconf.topology-singleton:1.2.1.Carbon]
at akka.actor.UntypedActor$$anonfun$receive$1.applyOrElse(UntypedActor.scala:165)[179:com.typesafe.akka.actor:2.4.18]
at akka.actor.Actor$class.aroundReceive(Actor.scala:502)[179:com.typesafe.akka.actor:2.4.18]
at akka.actor.UntypedActor.aroundReceive(UntypedActor.scala:95)[179:com.typesafe.akka.actor:2.4.18]
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:526)[179:com.typesafe.akka.actor:2.4.18]
at akka.actor.ActorCell.invoke(ActorCell.scala:495)[179:com.typesafe.akka.actor:2.4.18]
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)[179:com.typesafe.akka.actor:2.4.18]
at akka.dispatch.Mailbox.run(Mailbox.scala:224)[179:com.typesafe.akka.actor:2.4.18]
at akka.dispatch.Mailbox.exec(Mailbox.scala:234)[179:com.typesafe.akka.actor:2.4.18]
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)[175:org.scala-lang.scala-library:2.11.11.v20170413-090219-8a413ba7cc]
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)[175:org.scala-lang.scala-library:2.11.11.v20170413-090219-8a413ba7cc]
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)[175:org.scala-lang.scala-library:2.11.11.v20170413-090219-8a413ba7cc]
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)[175:org.scala-lang.scala-library:2.11.11.v20170413-090219-8a413ba7cc]

We tried with "merge", "create" and "replace" as the PATCH operations and saw the same error.

However the "remove" PATCH operation on the same call works and it removes the entry.

Request Type : PATCH

URL : http://controller:port/restconf/config/network-topology:network-topology/topology/topology-netconf/node/node/yang-ext:mount/exa-base:config/profile/dhcp-v4-server-profile/dhcp-profile-name/

Payload :

{
"ietf-restconf:yang-patch" :
{
"patch-id" : "0",
"edit" :
[

{ "edit-id" : "edit1", "operation" : "remove", "target" : "" }

]
}
}

This call successfully removes the entity.

SO I think the issue is is parsing the payload in the create/merge operations on mounted resources for the PATCH command in this scenario.



 Comments   
Comment by Robert Varga [ 20/Nov/17 ]

at org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.fromInstanceId(ImmutableNodes.java:136)[102:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]
at org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.createEditConfigAnyxml(NetconfMessageTransformUtil.java:294)[300:org.opendaylight.netconf.sal-netconf-connector:1.5.1.Carbon]

This is a mismatch of arguments coming from netconf: it should be a collection of individual entries, not the map node itself.

Comment by Balaji Varadaraju [ 29/Nov/17 ]

Thanks Robert. Can someone in NETCONF please further triage this?

Comment by Balaji Varadaraju [ 09/Feb/18 ]

We confirmed the call works for XML payloads and only has issues with JSON payloads. So either this is in netcong which parses the edit part of the patch request or in YANGTOOLS that does the conversion between JSON to normalized object.

Comment by Atul Gosain [ 20/Feb/18 ]

Following patch has been upstreamed to fix the issue https://git.opendaylight.org/gerrit/#/c/68436/

Restconf patch request to leaf lists contained in augmented nodes with JSON format payload, were not able to properly be formed into an edit-config structure to be sent to the device. More context of the problem at this https://lists.opendaylight.org/pipermail/yangtools-dev/2018-February/002157.html

Following ClassCastException exception was thrown when this payload was sent. Whereas the same payload in xml format result in a successful patch operation. The ImmutableMapNodeBuilder expects the normalizedNode to contain a list of MapEntryNode instead of MapEntryNode. This was happening because in case of JSON, the normalized node was being constructed with an additional layer of AugmentationNode whereas xml payload was not. 

java.lang.ClassCastException: org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder$ImmutableMapNode cannot be cast to org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode at org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder.withValue(ImmutableMapNodeBuilder.java:81)[94:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon] at org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder.withValue(ImmutableMapNodeBuilder.java:28)[94:org.opendaylight.yangtools.yang-data-impl:1.1.1.Carbon]

 

Generated at Wed Feb 07 20:15:09 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.