Ошибка Дублирование пространства имен во входных данных XML при получении списка через NETCONF с использованием 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. Я отследил проблему до тайм-аута akka.pattern.AskTimeoutException, который, по-видимому, вызван ошибкой синтаксического анализа ответа XML:

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 "child-element1" element "ChildElement1" 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

Неужели из-за списка? XML соответствует RFC 7950:

7.8.5. Правила кодирования XML

Список кодируется как последовательность элементов XML, по одному для каждой записи в списке. Локальное имя каждого элемента является идентификатором списка, а его пространство имен является пространством имен XML модуля (см. Раздел 7.1.3). Нет элемента XML, окружающего список в целом.

Любое предложение будет принято с благодарностью. Спасибо!


person amethyst    schedule 08.04.2020    source источник


Ответы (3)


Я не уверен, что знаю ответ здесь, но может ли проблема заключаться в том, что некоторые элементы списка называются одинаково? как в:

<ChildElement1 xmlns="child-element1">

Я знаю, что идентификаторы уникальны, но это то, что выделялось для меня.

person jamo    schedule 08.04.2020
comment
Да, но именно так вы делаете списки в XML, имя элемента не обязательно должно быть уникальным. Похоже, Opendaylight добавил это ограничение, но я понятия не имею, как с ним работать. - person amethyst; 09.04.2020
comment
Я также должен добавить, что список XML, который я опубликовал, был создан путем отправки команд POST в Opendaylight. Таким образом, я могу создавать ChildElements в конфигурации Netopeer2 и получать по одному элементу за раз, но не могу получить все XML-дерево. - person amethyst; 09.04.2020
comment
не могли бы вы открыть тикет jira для этой задачи со всеми кровавыми подробностями, чтобы воссоздать ее? Я могу попытаться найти время, чтобы продвинуть это вперед, но я здесь не эксперт. Может быть, таким образом мы сможем получить больше помощи. Вот jira: jira.opendaylight.org вам может потребоваться сначала получить LFID, чтобы вы могли войти в систему. Это здесь: identity.linuxfoundation.org - person jamo; 13.04.2020
comment
Спасибо за предложение @jamo. Я только что опубликовал ответ с тем, что, по моему мнению, может быть источником моей проблемы. Как вы думаете, стоит ли открывать тикет Jira? - person amethyst; 14.04.2020
comment
Я не совсем уверен на самом деле. Я не знаю, должен ли порядок элементов иметь значение или нет. Одна вещь, которая кажется мне странной, это то, что ваш комментарий о Мастере отсутствует в исходном посте. Я не слежу за этим. В любом случае, если у вас есть время и вы хотите отправить jira с инструкциями для обоих случаев здесь, я могу попытаться посмотреть, чему я могу научиться. Кажется, здесь что-то не так. - person jamo; 15.04.2020
comment
Я предполагаю, что синтаксический анализ завершается ошибкой из-за ошибки пространства имен Duplicate, из-за которой истекает время ожидания. Следовательно, мастер не работает, поскольку с момента получения ответа XML прошло 5 секунд. Зная происхождение проблемы, я нахожу оба сообщения об ошибках довольно обманчивыми, но, возможно, это только я :) - person amethyst; 16.04.2020
comment
похоже, что для этого был открыт тикет: jira.opendaylight.org/browse/NETCONF-692 - person jamo; 28.05.2020

Возможно, я на что-то наткнулся.
Я попробовал то же самое с другим сервером NETCONF (ConfD) и теми же моделями, и, похоже, все работает нормально.
Одно отличие, которое я заметил, заключается в том, что при выполнении get-request на TopElement или ParentElement, ConfD возвращает упорядоченные дочерние списки, т. е. сначала все элементы ChildElement1, а затем все элементы ChildElement2, даже если они были созданы в случайном порядке. Sysrepo-netopeer2, с другой стороны, возвращает XML-дерево с элементами в том же порядке, в котором они были созданы, поэтому элементы ChildElement1 и элементы ChildElement2 перемешаны (см. мой пример).
Я не уверен, что это так. оба хороших подхода, или если есть правильный и неправильный.

РЕДАКТИРОВАТЬ: В своем исходном сообщении я процитировал RFC 7950 и как-то пропустил соответствующую часть:

XML-элементы, представляющие записи списка, ДОЛЖНЫ появляться в порядке, указанном пользователем, если список "упорядочивается пользователем"; в противном случае порядок зависит от реализации. Элементы XML, представляющие записи списка, МОГУТ чередоваться с элементами для родственных элементов списка, если только список не определяет входные или выходные параметры RPC или действия.

Итак, если предположить, что я прав в своем предположении, похоже, что ODL в этом случае на самом деле слишком ограничивает.

person amethyst    schedule 14.04.2020

Я предполагаю, что проблема здесь в том, что ответ сервера содержит в /TopElement/ParentElement записи списка (в таком порядке):

  • Дочерний элемент1[id=1]
  • Дочерний элемент1[id=2]
  • Дочерний элемент2[id=1]
  • Дочерний элемент1[id=3]

Итак, я предполагаю, что и ChildElement1, и ChildElement2 являются списками. Проблема здесь в том, что 3 записи ChildElement1 не являются последовательными, у вас есть запись ChildElement2 посередине.

Я не вижу в спецификации NETCONF ничего, говорящего о том, что это проблема, но у OpenDaylight явно есть с этим проблемы. Я предполагаю, что OpenDaylight рассматривает обработку записи ChildElement2 как означающую, что список ChildElement1 закончился удалением, поэтому после того, как он найдет другую запись позже, он рассматривает ее как отдельный список и генерирует исключение Duplicate namespace "child-element1 " элемент "ChildElement1" во вводе XML, который у вас был.

Если вы хотите избежать этой проблемы, я бы рекомендовал отсортировать записи в ответе от сервера, чтобы записи одного и того же списка стояли вместе.

Итак, повторюсь, проблема заключается не в порядке отдельных записей списка, а в том, что вы чередуете записи, принадлежащие двум разным спискам.

person Paulo Gomes    schedule 09.05.2020