Error "Duplicate namespace in XML input" when retrieving a list over NETCONF using Opendaylight

huangapple 未分类评论49阅读模式
英文:

Error "Duplicate namespace in XML input" when retrieving a list over NETCONF using Opendaylight

问题

我正在使用OpenDaylight(版本0.10.1)作为NETCONF客户端,向Netopeer2服务器发送请求。我的YANG模型是一个由多个模块组成的第三方模型,其中包含多个列表元素等其他属性。这会转化为一个XML请求和响应对,看起来像这样(简化版本):

请求:

<rpc message-id="m-3" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
    <get-config>
        <source>
            <running/>
        </source>
        <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
            <TopElement xmlns="top-element">
                <id>1</id>
            </TopElement>
        </filter>
    </get-config>
</rpc>

响应:

<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="m-3">
    <data>
        <TopElement xmlns="top-element">
            <id>1</id>
            <ParentElement xmlns="parent-element">
                <id>1</id>
                <ChildElement1 xmlns="child-element1">
                    <id>1</id>
                    <attributes>
                        ...
                    </attributes>
                </ChildElement1>
                <ChildElement1 xmlns="child-element1">
                    <id>2</id>
                    <attributes>
                        ...
                    </attributes>
                </ChildElement1>
                <ChildElement2 xmlns="child-element2">
                    <id>1</id>
                    <attributes>
                        ...
                    </attributes>
                </ChildElement2>
                <ChildElement1 xmlns="child-element1">
                    <id>3</id>
                    <attributes>
                        ...
                    </attributes>
                </ChildElement1>
            </ParentElement>
        </TopElement>
    </data>
</rpc-reply>

然而,这样的请求引发了一个“主服务器宕机”错误,我尝试使用Karaf日志文件进行调查。我追踪到问题是由XML响应的解析错误引起的,出现了akka.pattern.AskTimeoutException超时:

2020-04-08T09:09:11,733 | ERROR | nioEventLoopGroupCloseable-3-1 | AbstractFuture                   | 42 - com.google.guava - 25.1.0.jre |  -  | RuntimeException while executing runnable CallbackListener{org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc$1@165744d4} with executor MoreExecutors.directExecutor()
java.lang.IllegalArgumentException: Failed to parse data response [data: null]
...
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[-1,-1]
Message: Duplicate namespace "child-element1" element "ChildElement1" in XML input
...

这可能真的是因为列表吗?XML符合RFC 7950

7.8.5. XML Encoding Rules

列表被编码为一系列XML元素,每个元素对应列表中的一个条目。每个元素的本地名称是列表的标识符,其命名空间是模块的XML命名空间(请参阅第7.1.3节)。没有包围整个列表的XML元素。

是否有任何建议将不胜感激。谢谢!

英文:

I am using Opendaylight (release 0.10.1) as NETCONF client to send requests to a Netopeer2 server.
My YANG model is a third-party model consisting of several modules which contain, among other attributes, several list elements.
This translates into an XML request and response pair that looks something like this (simplified):

Request:

&lt;rpc message-id=&quot;m-3&quot; xmlns=&quot;urn:ietf:params:xml:ns:netconf:base:1.0&quot;&gt;
	&lt;get-config&gt;
		&lt;source&gt;
			&lt;running/&gt;
		&lt;/source&gt;
		&lt;filter xmlns:ns0=&quot;urn:ietf:params:xml:ns:netconf:base:1.0&quot; ns0:type=&quot;subtree&quot;&gt;
			&lt;TopElement xmlns=&quot;top-element&quot;&gt;
				&lt;id&gt;1&lt;/id&gt;
			&lt;/TopElement&gt;
		&lt;/filter&gt;
	&lt;/get-config&gt;
&lt;/rpc&gt;

Response:

&lt;rpc-reply xmlns=&quot;urn:ietf:params:xml:ns:netconf:base:1.0&quot; message-id=&quot;m-3&quot;&gt;
	&lt;data&gt;
		&lt;TopElement xmlns=&quot;top-element&quot;&gt;
			&lt;id&gt;1&lt;/id&gt;
			&lt;ParentElement xmlns=&quot;parent-element&quot;&gt;
				&lt;id&gt;1&lt;/id&gt;
				&lt;ChildElement1 xmlns=&quot;child-element1&quot;&gt;
					&lt;id&gt;1&lt;/id&gt;
					&lt;attributes&gt;
						...
					&lt;/attributes&gt;
				&lt;/ChildElement1&gt;
				&lt;ChildElement1 xmlns=&quot;child-element1&quot;&gt;
					&lt;id&gt;2&lt;/id&gt;
					&lt;attributes&gt;
						...
					&lt;/attributes&gt;
				&lt;/ChildElement1&gt;
				&lt;ChildElement2 xmlns=&quot;child-element2&quot;&gt;
					&lt;id&gt;1&lt;/id&gt;
					&lt;attributes&gt;
						...
					&lt;/attributes&gt;
				&lt;/ChildElement2&gt;
				&lt;ChildElement1 xmlns=&quot;child-element1&quot;&gt;
					&lt;id&gt;3&lt;/id&gt;
					&lt;attributes&gt;
						...
					&lt;/attributes&gt;
				&lt;/ChildElement1&gt;
			&lt;/ParentElement&gt;
		&lt;/TopElement&gt;
	&lt;/data&gt;
&lt;/rpc-reply&gt;

However, such a request causes a "Master is down" error, which I have tried investigating using the Karaf log file. I tracked the problem down to a akka.pattern.AskTimeoutException timeout which seems to be caused by a parsing error of the XML response:

2020-04-08T09:09:11,733 | ERROR | nioEventLoopGroupCloseable-3-1 | AbstractFuture                   | 42 - com.google.guava - 25.1.0.jre |  -  | RuntimeException while executing runnable CallbackListener{org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc$1@165744d4} with executor MoreExecutors.directExecutor()
java.lang.IllegalArgumentException: Failed to parse data response [data: null]
	at org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer.toRpcResult(NetconfMessageTransformer.java:285) ~[386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer.toRpcResult(NetconfMessageTransformer.java:75) ~[386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc$1.onSuccess(NetconfDeviceRpc.java:60) ~[386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc$1.onSuccess(NetconfDeviceRpc.java:57) ~[386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at com.google.common.util.concurrent.Futures$CallbackListener.run(Futures.java:1355) ~[42:com.google.guava:25.1.0.jre]
	at com.google.common.util.concurrent.MoreExecutors$DirectExecutor.execute(MoreExecutors.java:398) ~[42:com.google.guava:25.1.0.jre]
	at com.google.common.util.concurrent.AbstractFuture.executeListener(AbstractFuture.java:1024) [42:com.google.guava:25.1.0.jre]
	at com.google.common.util.concurrent.AbstractFuture.complete(AbstractFuture.java:866) [42:com.google.guava:25.1.0.jre]
	at com.google.common.util.concurrent.AbstractFuture.set(AbstractFuture.java:689) [42:com.google.guava:25.1.0.jre]
	at org.opendaylight.netconf.sal.connect.netconf.listener.UncancellableFuture.set(UncancellableFuture.java:45) [386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator.processMessage(NetconfDeviceCommunicator.java:338) [386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator.onMessage(NetconfDeviceCommunicator.java:270) [386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator.onMessage(NetconfDeviceCommunicator.java:49) [386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	at org.opendaylight.netconf.nettyutil.AbstractNetconfSession.handleMessage(AbstractNetconfSession.java:64) [379:org.opendaylight.netconf.netty-util:1.6.1]
	at org.opendaylight.netconf.nettyutil.AbstractNetconfSession.channelRead0(AbstractNetconfSession.java:187) [379:org.opendaylight.netconf.netty-util:1.6.1]
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105) [71:io.netty.transport:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359) [71:io.netty.transport:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345) [71:io.netty.transport:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:337) [71:io.netty.transport:4.1.34.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323) [66:io.netty.codec:4.1.34.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) [66:io.netty.codec:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359) [71:io.netty.transport:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:345) [71:io.netty.transport:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:337) [71:io.netty.transport:4.1.34.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:323) [66:io.netty.codec:4.1.34.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:297) [66:io.netty.codec:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:359) [71:io.netty.transport:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:38) [71:io.netty.transport:4.1.34.Final]
	at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:350) [71:io.netty.transport:4.1.34.Final]
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) [68:io.netty.common:4.1.34.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) [68:io.netty.common:4.1.34.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:495) [71:io.netty.transport:4.1.34.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905) [68:io.netty.common:4.1.34.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [68:io.netty.common:4.1.34.Final]
	at java.lang.Thread.run(Thread.java:748) [?:?]
Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[-1,-1]
Message: Duplicate namespace &quot;child-element1&quot; element &quot;ChildElement1&quot; in XML input
	at org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream.read(XmlParserStream.java:383) ~[410:org.opendaylight.yangtools.yang-data-codec-xml:2.1.10]
	at org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream.read(XmlParserStream.java:321) ~[410:org.opendaylight.yangtools.yang-data-codec-xml:2.1.10]
	at org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream.read(XmlParserStream.java:403) ~[410:org.opendaylight.yangtools.yang-data-codec-xml:2.1.10]
	at org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream.read(XmlParserStream.java:321) ~[410:org.opendaylight.yangtools.yang-data-codec-xml:2.1.10]
	at org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream.read(XmlParserStream.java:403) ~[410:org.opendaylight.yangtools.yang-data-codec-xml:2.1.10]
	at org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream.parse(XmlParserStream.java:214) ~[410:org.opendaylight.yangtools.yang-data-codec-xml:2.1.10]
	at org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream.traverse(XmlParserStream.java:244) ~[410:org.opendaylight.yangtools.yang-data-codec-xml:2.1.10]
	at org.opendaylight.netconf.sal.connect.netconf.schema.mapping.NetconfMessageTransformer.toRpcResult(NetconfMessageTransformer.java:281) ~[386:org.opendaylight.netconf.sal-netconf-connector:1.9.1]
	... 34 more

Can it really be because of the list? The XML is compliant to RFC 7950:

> 7.8.5. XML Encoding Rules
>
> A list is encoded as a series of XML elements, one for each entry in
> the list. Each element's local name is the list's identifier, and its
> namespace is the module's XML namespace (see Section 7.1.3). There is
> no XML element surrounding the list as a whole.

Any suggestion would be greatly appreciated. Thanks!

答案1

得分: 0

抱歉,您提供的内容包含代码部分,根据您的要求,我将不会翻译代码。以下是翻译好的非代码部分:

我不确定我知道这里的答案,但问题可能只是一些列表项的名称相同?就像:

我知道 id 是唯一的,但这就是我注意到的。

英文:

I'm not sure I know the answer here, but could the problem just be that some
of the list items are named the same? as in:

&lt;ChildElement1 xmlns=&quot;child-element1&quot;&gt;

I know the id's are unique, but that's what stood out to me.

答案2

得分: 0

我可能偶然发现了一些内容。
我尝试了在不同的NETCONF服务器(ConfD)和相同的模型上进行相同的操作,似乎工作正常。
我注意到的一个区别是,在对TopElement或ParentElement执行get-request时,ConfD会按顺序返回子列表,即首先是所有ChildElement1元素,然后是所有ChildElement2元素,即使它们是以随机顺序创建的。另一方面,Sysrepo-netopeer2将XML树的元素按照创建顺序返回,因此ChildElement1元素和ChildElement2元素是混合在一起的(参见我的示例)。
我不确定它们是否都是好的方法,或者是否有对错之分。

编辑:在我的原始帖子中,我引用了RFC 7950,不过不知何故错过了相关部分:

> 如果列表是“ordered-by user”,则表示列表条目的XML元素必须按用户指定的顺序显示;否则,顺序取决于实现。表示列表条目的XML元素可以与列表的兄弟元素交错显示,除非列表定义了RPC或操作输入或输出参数。

因此,假设我对我的假设是正确的,看起来在这种情况下,ODL实际上过于限制了。

英文:

I might have stumbled upon something.
I tried the same thing with a different NETCONF server (ConfD) and the same models, and it seems to work fine.
One difference I noticed is that when doing a get-request on TopElement or ParentElement, ConfD returns the child lists ordered, i.e. first all ChildElement1 elements and then all ChildElement2 elements, even though they where created in a random order. Sysrepo-netopeer2, on the other hand, returns the XML tree with the elements in the same order as they were created, so ChildElement1 elements and ChildElement2 elements are mixed (see my example).
I'm not sure if they are both good approaches, or if there is a right one and a wrong one.

EDIT: In my original post I quoted RFC 7950 and somehow missed the relevant part:

> The XML elements representing list entries MUST appear in the order specified by the user if the list is "ordered-by user"; otherwise, the order is implementation dependent. The XML elements representing list entries MAY be interleaved with elements for siblings of the list, unless the list defines RPC or action input or output parameters.

So, assuming I am correct in my assumption, it looks like ODL is actually being too restrictive in this case.

答案3

得分: 0

问题在于服务器的响应在 /TopElement/ParentElement 处包含了以下顺序的列表条目:

  • ChildElement1[id=1]
  • ChildElement1[id=2]
  • ChildElement2[id=1]
  • ChildElement1[id=3]

因此,我认为 ChildElement1 和 ChildElement2 都是列表。问题在于 ChildElement1 的这 3 个条目不是连续的,你在中间插入了一个 ChildElement2 的条目。

我在 NETCONF 规范中没有看到关于这个问题的说明,但显然 OpenDaylight 存在问题。我猜想 OpenDaylight 认为处理 ChildElement2 条目意味着 ChildElement1 列表的声明已经结束,因此在稍后找到另一个条目后,它将其视为单独的列表,并生成了你遇到的异常 Duplicate namespace "child-element1" element "ChildElement1" in XML input

如果你想避免这个问题,我建议对服务器响应中的条目进行排序,以便同一列表的条目放在一起。

因此,重申一下,问题不在于单个列表条目的顺序,而在于你交错了属于两个不同列表的条目。

英文:

I guess the problem here is that the response from the server contains, at the /TopElement/ParentElement , the list entries (in this order):

  • ChildElement1[id=1]
  • ChildElement1[id=2]
  • ChildElement2[id=1]
  • ChildElement1[id=3]

So I assume both ChildElement1 and ChildElement2 are both lists.
The problem here is that the 3 entries of ChildElement1 are not sequential, you have an entry of ChildElement2 in the middle.

I don't see anything in the NETCONF spec saying that that is an issue, but clearly OpenDaylight has a problem with it.
I assume OpenDaylight consider the handling of the ChildElement2 entry as meaning that the ChildElement1 list has ended being delcared, so after it finds another entry later, it considers it as a separate list, and generates the exception Duplicate namespace "child-element1" element "ChildElement1" in XML input that you had.

If you want to avoid that problem, I'd recommend to sort the entries in the response from the server, so that entries of the same list stand together.

So to reiterate, the problem is not the order of individual list entries, but the fact that you are interleaving entries belonging to two different lists.

huangapple
  • 本文由 发表于 2020年4月8日 22:13:41
  • 转载请务必保留本文链接:https://java.coder-hub.com/61102825.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定