cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
3228
Views
0
Helpful
3
Replies

SUDS Issue adding Phone via Python

Aaron Dhiman
Level 1
Level 1

I am trying to add a phone with Python via AXL using SUDS/SUDS-jurko

Python version = 3.4

SUDS-Jurko - 0.6

AXL WSDL = 10.0

I am running into an issue where the CUCM "class" element needed to add a phone is being converted (I think by SUDS) to "cls" (I think b/c "class" is a keyword in Python).

The WSDL has a "class" element:

<xsd:element maxOccurs="1" minOccurs="1" name="class" nillable="false" type="axlapi:XClass">
     <xsd:annotation>
         <xsd:documentation>Class ID string. Class information is read-only except when creating a device.</xsd:documentation>
     </xsd:annotation>
</xsd:element>

<xsd:simpleType name="XClass">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Phone"/>
<xsd:enumeration value="Gateway"/>
<xsd:enumeration value="Conference Bridge"/>
<xsd:enumeration value="Media Termination Point"/>
<xsd:enumeration value="Route List"/>
<xsd:enumeration value="Voice Mail"/>
<xsd:enumeration value="CTI Route Point"/>
<xsd:enumeration value="Music On Hold"/>
<xsd:enumeration value="Simulation"/>
<xsd:enumeration value="Pilot"/>
<xsd:enumeration value="GateKeeper"/>
<xsd:enumeration value="Add-on modules"/>
<xsd:enumeration value="Hidden Phone"/>
<xsd:enumeration value="Trunk"/>
<xsd:enumeration value="Tone Announcement Player"/>
<xsd:enumeration value="Remote Destination Profile"/>
<xsd:enumeration value="EMCC Base Phone Template"/>
<xsd:enumeration value="EMCC Base Phone"/>
<xsd:enumeration value="Remote Destination Profile Template"/>
<xsd:enumeration value="Gateway Template"/>
<xsd:enumeration value="UDP Template"/>
<xsd:enumeration value="Phone Template"/>
<xsd:enumeration value="Device Profile"/>
<xsd:enumeration value="Invalid"/>
</xsd:restriction>


SUDS is converting the element name to "cls" instead of "class", which is not found and the request fails:

DEBUG:suds.mx.core:appending parent:

<phone uuid="{1016D6D4-60CF-EEC0-92D7-731B8187894F}" ctiid="2442">

   <name>CSF1</name>

   <description>Jabber Template for Migration</description>

   <product>Cisco Unified Client Services Framework</product>

   <model>Cisco Unified Client Services Framework</model>

</phone>

content:

(Content){

   tag = "cls"

   value = "Phone"

}

DEBUG:suds.mx.literal:starting content:

(Content){

   tag = "cls"

   value = "Phone"

}

DEBUG:suds.resolver:searching parent (<Complex:0x10e801c18 name="RPhone" />) for (cls)

Traceback (most recent call last):

  File "getPhone.py", line 94, in <module>

    client.service.addPhone(jabberObject['return'])

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/client.py", line 521, in __call__

    return client.invoke(args, kwargs)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/client.py", line 576, in invoke

    soapenv = binding.get_message(self.method, args, kwargs)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/bindings/binding.py", line 109, in get_message

    content = self.bodycontent(method, args, kwargs)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/bindings/document.py", line 95, in bodycontent

    add_param, self.options().extraArgumentErrors)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/argparser.py", line 83, in parse_args

    return arg_parser(args, kwargs, extra_parameter_errors)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/argparser.py", line 108, in __call__

    self.__process_parameters()

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/argparser.py", line 299, in __process_parameters

    self.__process_parameter(*pdef)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/argparser.py", line 294, in __process_parameter

    self.__in_choice_context(), value)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/bindings/document.py", line 86, in add_param

    p = self.mkparam(method, pdef, value)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/bindings/document.py", line 130, in mkparam

    return Binding.mkparam(self, method, pdef, object)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/bindings/binding.py", line 225, in mkparam

    return marshaller.process(content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/core.py", line 59, in process

    self.append(document, content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/core.py", line 72, in append

    self.appender.append(parent, content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/appender.py", line 88, in append

    appender.append(parent, content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/appender.py", line 229, in append

    Appender.append(self, child, cont)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/appender.py", line 168, in append

    self.marshaller.append(parent, content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/core.py", line 72, in append

    self.appender.append(parent, content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/appender.py", line 88, in append

    appender.append(parent, content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/appender.py", line 229, in append

    Appender.append(self, child, cont)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/appender.py", line 168, in append

    self.marshaller.append(parent, content)

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/core.py", line 71, in append

    if self.start(content):

  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/suds/mx/literal.py", line 86, in start

    raise TypeNotFound(content.tag)

suds.TypeNotFound: Type not found: 'cls'





Here is the call triggering the error, which is a request to add a device to CUCM:

  client.service.addPhone(jabberObject['return'])

This is what is being returned via the SUDS object:

**********DEBUG Jabber = ********************

(reply){

   return =

      (return){

         phone =

            (RPhone){

               _ctiid = 2442

               _uuid = "{1016D6D4-60CF-EEC0-92D7-731B8187894F}"

               name = "CSF1"

               description = "Jabber Template for Migration"

               product = "Cisco Unified Client Services Framework"

               model = "Cisco Unified Client Services Framework"

               cls = "Phone"

               protocol = "SIP"

               protocolSide = "User"

               callingSearchSpaceName =

//SEE THAT "CLASS" IS CONVERTED TO "CLS"

3 Replies 3

dstaudt
Cisco Employee
Cisco Employee

You may have to try working with the WSDL consumer framework developer to identify a workaround, or given the source maybe you can reverse-engineer one.

FWIW, if this is just a small POC or similar, it's not necessary to use the WSDL+compile path, you can just treat the AXL requests as XML over HTTP and build requests using XML objects or via simple text manipulation (XML template generated via soapUI:)

for i in xrange(1,33):

    xml="""<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/10.5">

      <soapenv:Header/>

        <soapenv:Body>

          <ns:addLine>

            <line>

              <pattern>1{0}</pattern>

            </line>

          </ns:addLine>

        </soapenv:Body>

      </soapenv:Envelope>""".format(str(i).zfill(3) )

    headers = {'Content-Type': 'text/xml',

        'SOAPAction': '"CUCM:DB ver=10.5 addLine"'

        }

    req=requests.post('https://'+host+':8443'+'/axl/', auth=(userName,password), data=xml, headers=headers, verify=False)

I ran into this same problem. My idea was to do a "getPhone" or "getDeviceProfile" request, modify attributes of the returned object, and then perform an "update" request using that object. To try and workaround this, I even went as far as to create a new object, translate the old object to a dictionary so I could iterate over it better, and copy all of the attributes that were present (some attributes aren't listed in the AXL Scheme for an update request).

from suds.sudsobject import asdict

newdp = client.factory.create('ns0:XDeviceProfile')

olddp = client.service.getDeviceProfile(name='TEST123')[1]['return'].deviceProfile

## Convert deviceProfile object to a dict. Maybe not necessary....

d = asdict(olddp)

for item in d:

    ## Check if the particular key is also in the factory created object, if not skip the loop

    if hasattr(newdp, item):

        newdp[item] = d[item]

    elif item is 'cls':

       ## Change the "cls" to "class"

       newdp['class'] = d[item]

The problem I ran into after this, is basically it was sending out a SOAP request with the entire object contents as text within the <name></name> tags, which returned a "could not find object NAME123DescriptionCommonPhoneProfile", etc. In the end I realised, there isn't much sense in doing this for an update object anyway, since I could more simply perform an update specifying only the tags I want. I don't need to import every attribute again.

If you're just trying to add a device, you can use the factory.create method, modify the object, and then send an "add" request. i.e.

dp = client.factory.create('ns0:XDeviceProfile')

dp.name = "NAME"
dp.description = "Description"
dp.protocol = "SIP"
dp.product = "Cisco 7965"
dp.protocolSide = "User"
dp.phoneTemplateName.value = "Standard 7965 SIP"
dp['class'] = "Device Profile"

client.service.addDeviceProfile(dp)

As you can see, I still needed to refer to the <class> tags differently to the rest, but this works for me. Also the method I wrote above works for building an XDeviceProfile object and copying all the attributes from a getDeviceProfile request.

I'm still pretty new at this too, so there's probably much nicer ways.....

FYI I'm using Python 2.7, suds-jurko 6.0 and AXL Schema 10.5

Hi,

I have been able to add a standard UDP using the suds Client.Service method (I havent used the factory create as yet) as this was a quick test.

The below code adds a device successfully on CUCM v11, python 3.4, suds Jurko 0.6 -

client = Client(location=url, url=wsdl1, retxml=True, username=username, password=password)

x = client.service.addDeviceProfile({'name': 'TEST_UDP_5702_7965', 'description': 'Mitch Test UDP SOAP',
   'product': 'Cisco 7965', 'protocol': 'SCCP', 'class': 'Device Profile',
   'phoneTemplateName': 'Standard 7965 SCCP'})

print(x)

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: