мыльная пена: неправильный маршалинг массива массивов

#soap #suds

#soap #мыльная пена

Вопрос:

Я пытаюсь поговорить с балансировщиком нагрузки (Zeus ZXTM) с помощью python:

 a = client.factory.create('StringArrayArray')
b = client.factory.create('StringArray')
b.value = ['node01:80',]
a.value = [b,]
client.service.addDrainingNodes(['my pool'], a)
  

Но я получаю следующую ошибку:

пена.Веб-ошибка: ошибка сервера: «Нет ссылки на МАССИВ в / usr/local/zeus/zxtmadmin/lib /perl/Zeus/ZXTM/SOAPBase.pm строка 772.

Выдержка из определения схемы:

     <types>
        <xsd:schema targetNamespace='http://soap.zeus.com/zxtm/1.0/'
            xmlns='http://www.w3.org/2001/XMLSchema'
            xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/'
            xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'>

            <xsd:complexType name="StringArray">
                <xsd:complexContent>
                    <xsd:restriction base='SOAP-ENC:Array'>
                        <xsd:attribute ref='SOAP-ENC:arrayType' wsdl:arrayType='xsd:string[]'/>
                    </xsd:restriction>
                </xsd:complexContent>
            </xsd:complexType>

            <xsd:complexType name="StringArrayArray">
                <xsd:complexContent>
                    <xsd:restriction base='SOAP-ENC:Array'>
                        <xsd:attribute ref='SOAP-ENC:arrayType' wsdl:arrayType='zeusns:StringArray[]'/>
                    </xsd:restriction>
                </xsd:complexContent>
            </xsd:complexType>
        </xsd:schema>
    </types>

    <message name="addDrainingNodesRequest">
        <part name="names" type="zeusns:StringArray" />
        <part name="values" type="zeusns:StringArrayArray" />
    </message>

    <message name="addDrainingNodesResponse"></message>

    <portType name="PoolPort">

        <operation name="addDrainingNodes">
            <documentation>
                Add nodes to the lists of draining nodes, for each of the named pools.
            </documentation>

            <input message="zeusns:addDrainingNodesRequest"/>
            <output message="zeusns:addDrainingNodesResponse"/>
        </operation>
    </portType>
</definitions>
  

Я также пробовал вот так:
client.service.addDrainingNodes([‘мой пул’], [[‘node01:80’]])
которое работало в SOAPpy, но теперь в suds я получаю:

пена.Веб-ошибка: ошибка сервера: «Значение не является массивом»

Сравнение того, что отправляет SOAPpy, и того, что отправляет suds:

SOAPpy (работает):

 <ns1:addDrainingNodes xmlns:ns1="http://soap.zeus.com/zxtm/1.0/Pool/" SOAP-ENC:root="1">
    <v1 SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array">
        <item>my pool</item>
    </v1>
    <v2 SOAP-ENC:arrayType="xsd:list[1]" xsi:type="SOAP-ENC:Array">
        <item SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array">
            <item>node01:80</item>
        </item>
    </v2>
</ns1:addDrainingNodes>
  

suds (не работает):

 <ns4:addDrainingNodes>
    <names xsi:type="ns0:StringArray" ns3:arrayType="ns2:string[1]">
        <item xsi:type="ns2:string">my pool</item>
    </names>
    <values xsi:type="ns0:StringArrayArray" ns3:arrayType="ns0:StringArray[1]">
        <item xsi:type="ns2:string">node01:80</item>
    </values>
</ns4:addDrainingNodes>
  

Контекст:

  • Я новичок в suds и Soap
  • для ZXTM loadbalancer есть только SOAP-интерфейс
  • использование python2.6 и suds 0.3.9
  • раньше мы использовали SOAPpy от ZSI, но у нас были проблемы с его использованием в python 2.6

Редактировать: добавлены полезные нагрузки suds / SOAPpy

Ответ №1:

После попытки

  • миллионы различных аргументов для этой функции
  • wsdl2py из ZSI

Я узнал, что suds 4.0 предлагает плагины, которые решают эту проблему путем взлома, но, тем не менее, я думаю, что это ошибка suds:

 class FixArrayPlugin(Plugin):
    def sending(self, context):
        command = context.envelope.getChild('Body').getChildren()[0].name
        if command == 'addDrainingNodes':
            context.envelope.addPrefix('xsd', 'http://www.w3.org/1999/XMLSchema')
            values = context.envelope.getChild('Body').getChild('addDrainingNodes').getChild('values')
            values.set('SOAP-ENC:arrayType', 'xsd:list[1]')
            values.set('xsi:type', 'SOAP-ENC:Array')
            item = values[0]
            item.set('SOAP-ENC:arrayType', 'xsd:list[1]')
            item.set('xsi:type', 'SOAP-ENC:Array')

client = Client(wsdl, location=location, plugins=[FixArrayPlugin()])
a = client.factory.create('StringArrayArray')
b = client.factory.create('StringArray')
b.item = ['node01:80']
a.item = [b,]
client.service.addDrainingNodes(['my pool'], a)
  

Я с нетерпением жду, когда эта проблема будет исправлена, ИМО, это должно быть однострочным
Я оставляю это открытым, поскольку меня все еще интересуют лучшие альтернативы

Ответ №2:

Что мне кажется странным, так это то, что вам приходится явно создавать типы типа ‘StringArrayArray’ и ‘stringArray’ — достаточно умный SOAP-клиент на таком языке, как python, должен быть в состоянии выяснить это с помощью отражения, изучая аргументы, которые вы передаете вызову службы. Я предполагаю, что они объявлены в wsdl как что-то вроде «SOAP-ENC: Array» — если это так, то они не предназначены для того, чтобы быть объектами. Это также имело бы смысл с сообщением об ошибке «Не ссылка на массив». Вы пробовали просто;

 a = [ ['node01:80',], ]
client.service.addDrainingNodes(['my pool'], a)
  

Или, возможно, сбой…

 a = client.factory.create('StringArrayArray')
b = ['node01:80',]
a.value = [ b, ]
client.service.addDrainingNodes(['my pool'], a)
  

Удачи.

Комментарии:

1. хм, безуспешно попробовал оба варианта.. Действительно, suds должен уметь создавать сложные типы, но это где-то не удается, также теперь также открыт билет trac: fedorahosted.org/suds/ticket/340