cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
6925
Views
20
Helpful
14
Replies

Python - AXL - ZEEP failing to add line

Keith Abbott
Level 1
Level 1

Hi All,

 

This is basically an offshoot of post https://community.cisco.com/t5/management/python-with-axl-updatephone-fail/m-p/4031354/highlight/false#M3313.

 

I took the excellent suggestions made by npetrele, and reviewed the demo at https://developer.cisco.com/learning/lab/python-zeep-axl-lab/step/1

 

That demo takes me much further toward my end-goal, which is to create an axl-based supercopy.

 

I grabbed the code from that project as a starting point, and thus far have only modified the call manager connection info, wsdl file location, and added a getpass for the password.

 

However when running, I get errors. I will post the code and errors below.

I can tell from the errors that it is having a problem with the addline request, and that it doesnt think the returned XML has a valid root element. But frankly I dont know where to go from there.

 

I would appreciate any help you can give on the error, and even more, any help you can give on troubleshooting methods for this type of problem - Id like to get to the point where I can figure this stuff out on my own!

I am running against a CUCM 10.5, python version 3.6.7 (32 bit on a 64-bit machine), and Eclipse IDE 4.13

 

thanks

 

 

from lxml import etree
from requests import Session
from requests.auth import HTTPBasicAuth

from zeep import Client, Settings, Plugin
from zeep.transports import Transport
from zeep.cache import SqliteCache
from zeep.plugins import HistoryPlugin
from zeep.exceptions import Fault
import getpass

#Local AXL File file://C:/AXLdev/AXLAPI.wsd
WSDL_URL = 'file://C:/AXLdev/AXLAPI.wsdl'

# These are sample values for DevNet sandbox
# replace them with values for your own CUCM, if needed
CUCM_URL = 'https://LabServer.Mycompany.com'
#CUCM_URL = 'https://10.10.20.1:8443/axl/'
USERNAME = 'MyUN'
#PASSWD = 'ciscopsdt'
PASSWD = getpass.getpass()

# If you have a pem file certificate for CUCM, uncomment and define it here
#CERT = 'some.pem'

# These values should work with a DevNet sandbox
# You may need to change them if you are working with your own CUCM server
# and that server already has a line DN of 1111, or in the extremely unlikely
# event that you have a johnq public and a phone with a MAC address of 151515151515

LINEDN = '1111'
PHONEID = 'SEP151515151515'
USERID = 'johnq'
USERFNAME = 'johnq'
USERLNAME = 'public'
USERPASS = 'public'

# history shows http_headers
history = HistoryPlugin()

# This class lets you view the incoming and outgoing http headers and XML
class MyLoggingPlugin(Plugin):

    def ingress(self, envelope, http_headers, operation):
        print(etree.tostring(envelope, pretty_print=True))
        return envelope, http_headers

    def egress(self, envelope, http_headers, operation, binding_options):
        print(etree.tostring(envelope, pretty_print=True))
        return envelope, http_headers

# ***** Set Up Soap Client *****    
session = Session()

#session.verify = CERT
session.verify = False
session.auth = HTTPBasicAuth(USERNAME, PASSWD)

transport = Transport(session=session, timeout=10, cache=SqliteCache())

# strict=False is not always necessary, but it allows zeep to parse imperfect XML
settings = Settings(strict=False, xml_huge_tree=True)

client = Client(WSDL_URL, settings=settings, transport=transport, plugins=[MyLoggingPlugin(),history])

service = client.create_service("{http://www.cisco.com/AXLAPIService/}AXLAPIBinding", CUCM_URL)

# *****     ******

# ===== set up Line =====
line_data = {
    'line': {
        'pattern': LINEDN,
        'description': 'Test Line',
        'usage': 'Device',
        'routePartitionName': None
    }
}

# the ** before line_data tells the Python function to expect
# an unspecified number  of keyword/value pairs

try:
  line_resp = service.addLine(**line_data)
except Fault as err:
  print("Zeep error: {0}".format(err))
else:
  print("\naddLine response:\n")
  print(line_resp,"\n")
  print(history.last_sent)
  print(history.last_received)
  
# =====     ======

# ******* AddPhone SEP151515151515 *******
phone_data = {
    'phone': {
        'name': PHONEID,
        'description': PHONEID,
        'product': 'Cisco 8821',
        'class': 'Phone',
        'protocol': 'SIP',
        'devicePoolName': {
            '_value_1': 'Default'
        },
        'commonPhoneConfigName': {
            '_value_1': 'Standard Common Phone Profile'
        },
        'networkLocation': 'Use System Default',
        'locationName': {
            '_value_1': 'Hub_None'
        },
        'mlppIndicationStatus': 'Default',
        'preemption': 'Default',
        'useTrustedRelayPoint': 'Default',
        'retryVideoCallAsAudio': 'true',
        'securityProfileName': {
            '_value_1': 'Cisco 8821 - Standard SIP Non-Secure Profile'
        },
        'sipProfileName': {
            '_value_1': 'Standard SIP Profile'
        },
        'lines': {
            'line': [
                {
                    'index': 1,
                    'dirn': {
                        'pattern': LINEDN,
                        'routePartitionName': None
                    },
                    'ringSetting': 'Use System Default',
                    'consecutiveRingSetting': 'Use System Default',
                    'ringSettingIdlePickupAlert': 'Use System Default',
                    'ringSettingActivePickupAlert': 'Use System Default',
                    'missedCallLogging': 'true',
                    'recordingMediaSource': 'Gateway Preferred',
                }
            ],
        },
        'phoneTemplateName': {
            '_value_1': 'Standard 8821 SIP'
        },
        'ringSettingIdleBlfAudibleAlert': 'Default',
        'ringSettingBusyBlfAudibleAlert': 'Default',
        'enableExtensionMobility': 'false',
        'singleButtonBarge': 'Off',
        'joinAcrossLines': 'Off',
        'builtInBridgeStatus': 'Default',
        'callInfoPrivacyStatus': 'Default',
        'hlogStatus': 'On',
        'ignorePresentationIndicators': 'false',
        'allowCtiControlFlag': 'true',
        'presenceGroupName': {
            '_value_1': 'Standard Presence group'
        },
        'unattendedPort': 'false',
        'requireDtmfReception': 'false',
        'rfc2833Disabled': 'false',
        'certificateOperation': 'No Pending Operation',
        'dndOption': 'Use Common Phone Profile Setting',
        'dndStatus': 'false',
        'isActive': 'true',
        'isDualMode': 'false',
        'phoneSuite': 'Default',
        'phoneServiceDisplay': 'Default',
        'isProtected': 'false',
        'mtpRequired': 'false',
        'mtpPreferedCodec': '711ulaw',
        'outboundCallRollover': 'No Rollover',
        'hotlineDevice': 'false',
        'alwaysUsePrimeLine': 'Default',
        'alwaysUsePrimeLineForVoiceMessage': 'Default',
        'deviceTrustMode': 'Not Trusted',
        'earlyOfferSupportForVoiceCall': 'false'
    }
}

try:
  phone_resp = service.addPhone(**phone_data)
except Fault as err:
  print("Zeep error: {0}".format(err))
else:
  print("\naddPhone response:\n")
  print(phone_resp,"\n")
  print(history.last_sent)
  print(history.last_received)
  
  # *******     *******
  
  # ========== Add EndUser johnq ==========
  
  user_data = {
    'user': {
        'firstName': USERFNAME,
        'lastName': USERLNAME,
        'userid': USERID,
        'password': USERPASS,
        'pin': '5555',
        'userLocale': 'English United States',
        'associatedDevices': {
            'device': [
                PHONEID
            ]
        },
        'primaryExtension': {
            'pattern': LINEDN,
            'routePartitionName': None
        },
        'associatedGroups': {
            'userGroup': [
                {
                    'name': 'Standard CCM End Users',
                    'userRoles': {
                        'userRole': [
                            'Standard CCM End Users',
                            'Standard CCMUSER Administration'
                        ]
                    }
                },
                {
                    'name': 'Standard CTI Enabled',
                    'userRoles': {
                        'userRole': [
                            'Standard CTI Enabled'
                        ]
                    }
                },
                {
                    'name': 'Third Party Application Users'
                },
                {
                    'name': 'Application Client Users'
                }
            ]
        },
        'enableCti': 'true',
        'presenceGroupName': {
            '_value_1': 'Standard Presence group'
        },
        'enableMobility': 'true',
        'enableMobileVoiceAccess': 'true',
        'maxDeskPickupWaitTime': 10000,
        'remoteDestinationLimit': 4,
        'passwordCredentials': {
            'pwdCredPolicyName': {
                '_value_1': 'Default Credential Policy'
            }
        },
        'enableEmcc': 'false',
        'homeCluster': 'true',
        'imAndPresenceEnable': 'true',
        'calendarPresence': 'false'
    }
}

try:
  user_resp = service.addUser(**user_data)
except Fault as err:
  print("Zeep error: {0}".format(err))
else:
  print("\naddUser response:\n")
  print(user_resp,"\n")
  print(history.last_sent)
  print(history.last_received)
  
  # ==========     ==========
  
  # **********  Associate User With Phone  **********
  phone_data = {
    'name': PHONEID,
    'ownerUserName': USERID,
    'lines': {
        'line': [
            {
                'index': 1,
                'dirn': {
                    'pattern': LINEDN,
                    'routePartitionName': None
                },
                'associatedEndusers': {
                    'enduser': [
                        {
                            'userId': USERID
                        }
                    ]
                }
            }
        ],
    }
}

try:
  phone_resp = service.updatePhone(**phone_data)
except Fault as err:
  print("Zeep error: {0}".format(err))
else:
  print("\nupdatePhone response:\n")
  print(phone_resp,"\n")
  print(history.last_sent)
  print(history.last_received)
  
  # **********     **********
  
  

The errors I get are:

b'<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">\n  <soap-env:Body>\n    <ns0:addLine xmlns:ns0="http://www.cisco.com/AXL/API/10.5">\n      <line>\n        <pattern>1111</pattern>\n        <description>Test Line</description>\n        <usage>Device</usage>\n      </line>\n    </ns0:addLine>\n  </soap-env:Body>\n</soap-env:Envelope>\n'
C:\Program Files (x86)\Python36-32\lib\site-packages\urllib3\connectionpool.py:1004: InsecureRequestWarning: Unverified HTTPS request is being made to host 'usfel1-ucl201.corp.pattersoncompanies.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
  InsecureRequestWarning,
b'<html>\n    <head>\n        <style type="text/css">\n            a {\n                color: #316984;\n                text-decoration: none;\n            }\n\n            a:hover {\n                color: #316984;\n                text-decoration: underline;\n            }\n\n            a:visted {\n                color: #316984;\n                text-decoration: none;\n            }\n\n            body {\n                background-attachment: fixed;\n                background-color: #ffffff;\n                background-repeat: no-repeat;\n                color: #316984;\n                font-family: arial,helvetica,sans-serif;\n            }\n\n            #content {\n                border: 1px solid #d6d7d6;\n                font-size: 93.5%;\n                margin: 0px 10% 30px 10%;\n            }\n\n            #content-header {\n                background-color: #eeeeee;\n                border-bottom: 1px solid #666666;\n                color: #666666;\n                font-size: 124.5%;\n                padding: 5px 15px 5px 15px;\n            }\n\n            #copyright {\n                font-size: 75%;\n                margin: 0px 10% 0px 10%;\n                padding: 3px 0px 0px 0px;\n                text-align: right;\n            }\n\n            img {\n                display: block;\n                margin: 0px 0px 20px 0px;\n            }\n\n            #logo {\n                margin: 30px 10% 0px 10%;\n            }\n\n            p {\n                padding: 5px 15px 5px 15px;\n            }\n\n            pre {\n                padding: 5px 15px 5px 30px;\n            }\n        </style>\n    </head>\n    <body>\n\n        <div id="logo">\n            <img src="ciscologo.gif" alt="Cisco Systems logo"/>\n        </div>\n\n        <div id="content">\n            <div id="content-header">\n                Installed Applications\n            </div>\n            <p>\n                \n                <ul>\n\n                \n                    <li>\n                        <a href="ccmadmin/showHome.do">Cisco Unified Communications Manager</a>\n                \n                \n                    </li>\n                \n                    <li>\n                        <a href="ucmuser">Cisco Unified Communications Self Care Portal</a>\n                \n                \n                    </li>\n                \n                    <li>\n                        <a href="elm-admin">Cisco Prime License Manager</a>\n                \n                \n                    </li>\n                \n                </ul>\n                \n            </p>\n        </div>\n        \n        \n\n        <div id="content">\n            <div id="content-header">\n                Cryptographic Features\n            </div>\n            <p>\n                This product contains cryptographic features and is subject to United States and local country laws governing import, export, transfer and use. Delivery of Cisco cryptographic products does not imply third-party authority to import, export, distribute or use encryption. Importers, exporters, distributors and users are responsible for compliance with U.S. and local country laws. By using this product you agree to comply with applicable laws and regulations. If you are unable to comply with U.S. and local laws, return this product immediately.\n            </p>\n            <p>\n                A summary of U.S. laws governing Cisco cryptographic products may be found at: <a href="http://tools.cisco.com/legal/export/pepd/Search.do">http://tools.cisco.com/legal/export/pepd/Search.do</a>\n            </p>\n            <p>\n                If you require further assistance please contact us by sending email to <a href="mailto:export@cisco.com">export@cisco.com</a>.\n            </p>\n        </div>\n\n    </body>\n</html>\n'
Traceback (most recent call last):
  File "C:\Users\t01136.POS\eclipsePython-workspace\AXL-SOAP2\MyZeep1.py", line 85, in <module>
    line_resp = service.addLine(**line_data)
  File "C:\Program Files (x86)\Python36-32\lib\site-packages\zeep\proxy.py", line 45, in __call__
    kwargs,
  File "C:\Program Files (x86)\Python36-32\lib\site-packages\zeep\wsdl\bindings\soap.py", line 130, in send
    return self.process_reply(client, operation_obj, response)
  File "C:\Program Files (x86)\Python36-32\lib\site-packages\zeep\wsdl\bindings\soap.py", line 197, in process_reply
    result = operation.process_reply(doc)
  File "C:\Program Files (x86)\Python36-32\lib\site-packages\zeep\wsdl\bindings\soap.py", line 392, in process_reply
    % (envelope_qname.namespace, envelope.tag)
zeep.exceptions.XMLSyntaxError: The XML returned by the server does not contain a valid {http://schemas.xmlsoap.org/soap/envelope/}Envelope root element. The root element found is html 

 

 

 

 

1 Accepted Solution

Accepted Solutions

Yeah, you can't add the same line twice until you delete the line on the server. I get around this by just trying to update the line if the add fails. It means I have to have two different xml objects but that was easy to setup

 

    try:
        req = service.addLine(**addline)
        print("Successfully Created phone line")
    except Fault:
        show_history()
        try:
            req = service.updateLine(**updateline)
            print("Successfully updated the existing phone line")
        except Fault:
            show_history()

View solution in original post

14 Replies 14

Keith Abbott
Level 1
Level 1

Group,

 

I found the issue.

 

for posterity, I botched the URL for the cucm axl service.

# had - incorrect
CUCM_URL = 'https://Lab.Mycompany.com/'


#changed - correct
CUCM_URL = 'https://Lab.Mycompany.com:8443/axl/'

After modifying - it successfully created the line - but failed subsequent steps - I will add more after looking it over.

thanks

Hi , I am new in AXL and have a simple question. I reviewed several AXL scripts and didn't find on any of them references to the database tables when adding, changing lines or users or devices,  as I do when run SQL directly from CUCM cli. In every sql request i have to show which table i am connecting and modifying.  But AXL looks like somehow does it itself??

True!  AXL is an abstraction layer that provides a bunch of requests that (mostly) end up manipulating the database, similarly to how the admin UI does things.  It's (usually) a lot easier to figure out how to do something using AXL, then to try and discern all the tables/fields/keys/constraints in the truly enormous CUCM database...

ok. The code from the demo has definitely moved me along toward the goal of an axl-based supercopy.

 

However Ive hit a sticking point I cant quite figure out.

I am grabbing all of the information from the super-copy source phone with a 'getphone'. Then I put a few key bits of information into variables for use in the addphone or addline statement (shown in the original code).

 

Ive advanced an item at a time and the method has been working without issue. However I am now trying specifiy an existing route partition to the line. According to everything I can find, the correct name should be 'routePartitionName'. Ive tried pulling that specific data from both getline and getphone. When I print the entire return, I can see the route partition, but but when I try to assign it to a variable, I get an error indicating the instance has no such attribute - I'll include a sample of the code grabbing the data, the return data, and the errors, below.

 

#get data from getline
uuid_lookup = '0A2A0CB1-5384-91A5-CF21-F0587AD1450F'
try:
    resp3 = service.getLine(uuid=uuid_lookup)
   print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
    print(resp3) #print entire return
    test = resp3.routePartitionName #grab just RPN
    print("TEST:",test)             #and print it
    print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
    Lphone = resp['return'].phone
except Fault:
  print("$$$$$$$$$$$$   getline failed   $$$$$$$$$$$$$$$")
  print(history.last_sent)
  print(history.last_received)

  print("$$$$$$$$$$$$   ")

Below is a sample of the return, and the errors:

 

b'<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">\n  <soap-env:Body>\n    <ns0:listPhone xmlns:ns0="http://www.cisco.com/AXL/API/10.5">\n      <searchCriteria>\n        <name>SEP00AF1F9C5D7A</name>\n      </searchCriteria>\n      <returnedTags>\n        <name></name>\n        <description></description>\n        <callingSearchSpaceName></callingSearchSpaceName>\n      </returnedTags>\n    </ns0:listPhone>\n  </soap-env:Body>\n</soap-env:Envelope>\n'
b'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/10.5">\n  <soapenv:Body>\n    <ns:listPhoneResponse>\n      <return>\n        <phone uuid="{D58FB7A2-E0FF-8C5E-091A-6DAB641271AE}">\n          <name>SEP00AF1F9C5D7A</name>\n          <description>Jonas Grumby</description>\n          <callingSearchSpaceName uuid="{A37079FB-71F7-4AA8-E6C5-059F2059FA22}">Lab</callingSearchSpaceName>\n        </phone>\n      </return>\n    </ns:listPhoneResponse>\n  </soapenv:Body>\n</soapenv:Envelope>\n'
==========   print listphone   ===========
===
SEP00AF1F9C5D7A ---1--- Jonas Grumby ---1--- {D58FB7A2-E0FF-8C5E-091A-6DAB641271AE}
Tuuid1: {D58FB7A2-E0FF-8C5E-091A-6DAB641271AE}
pProduct1: None
pModel1: None
b'<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">\n  <soap-env:Body>\n    <ns0:getLine xmlns:ns0="http://www.cisco.com/AXL/API/10.5">\n      <uuid>0A2A0CB1-5384-91A5-CF21-F0587AD1450F</uuid>\n    </ns0:getLine>\n  </soap-env:Body>\n</soap-env:Envelope>\n'
b'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">\n  <soapenv:Body>\n    <ns:getLineResponse xmlns:ns="http://www.cisco.com/AXL/API/10.5">\n      <return>\n        <line uuid="{0A2A0CB1-5384-91A5-CF21-F0587AD1450F}">\n          <pattern>\\+16513812380</pattern>\n          <description>Captain America</description>\n          <usage>Device</usage>\n          <routePartitionName uuid="{D4452A77-D11C-0810-C506-D09974A022CC}">Lab</routePartitionName>\n          <aarNeighborhoodName/>\n          <aarDestinationMask/>\n          <aarKeepCallHistory>true</aarKeepCallHistory>\n          <aarVoiceMailEnabled>false</aarVoiceMailEnabled>\n          <callForwardAll>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <secondaryCallingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardAll>\n          <callForwardBusy>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardBusy>\n          <callForwardBusyInt>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardBusyInt>\n          <callForwardNoAnswer>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n            <duration/>\n          </callForwardNoAnswer>\n          <callForwardNoAnswerInt>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n            <duration/>\n          </callForwardNoAnswerInt>\n          <callForwardNoCoverage>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardNoCoverage>\n          <callForwardNoCoverageInt>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardNoCoverageInt>\n          <callForwardOnFailure>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardOnFailure>\n          <callForwardAlternateParty>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n            <duration/>\n          </callForwardAlternateParty>\n          <callForwardNotRegistered>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardNotRegistered>\n          <callForwardNotRegisteredInt>\n            <forwardToVoiceMail>false</forwardToVoiceMail>\n            <callingSearchSpaceName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n            <destination/>\n          </callForwardNotRegisteredInt>\n          <callPickupGroupName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" uuid=""/>\n          <autoAnswer>Auto Answer Off</autoAnswer>\n          <networkHoldMohAudioSourceId/>\n          <userHoldMohAudioSourceId/>\n          <alertingName>Captain America</alertingName>\n          <asciiAlertingName>Captain America</asciiAlertingName>\n          <presenceGroupName uuid="{AD243D17-98B4-4118-8FEB-5FF2E1B781AC}">Standard Presence group</presenceGroupName>\n          <shareLineAppearanceCssName uuid="{A37079FB-71F7-4AA8-E6C5-059F2059FA22}">Lab</shareLineAppearanceCssName>\n          <voiceMailProfileName/>\n          <patternPrecedence>Default</patternPrecedence>\n          <releaseClause>No Error</releaseClause>\n          <hrDuration/>\n          <hrInterval/>\n          <cfaCssPolicy>Use System Default</cfaCssPolicy>\n          <defaultActivatedDeviceName/>\n          <parkMonForwardNoRetrieveDn/>\n          <parkMonForwardNoRetrieveIntDn/>\n          <parkMonForwardNoRetrieveVmEnabled>false</parkMonForwardNoRetrieveVmEnabled>\n          <parkMonForwardNoRetrieveIntVmEnabled>false</parkMonForwardNoRetrieveIntVmEnabled>\n          <parkMonForwardNoRetrieveCssName/>\n          <parkMonForwardNoRetrieveIntCssName/>\n          <parkMonReversionTimer/>\n          <partyEntranceTone>Default</partyEntranceTone>\n          <directoryURIs/>\n          <allowCtiControlFlag>true</allowCtiControlFlag>\n          <rejectAnonymousCall>false</rejectAnonymousCall>\n          <patternUrgency>false</patternUrgency>\n          <confidentialAccess>\n            <confidentialAccessMode/>\n            <confidentialAccessLevel>-1</confidentialAccessLevel>\n          </confidentialAccess>\n          <externalCallControlProfile/>\n          <enterpriseAltNum>\n            <numMask/>\n            <isUrgent>f</isUrgent>\n            <addLocalRoutePartition>f</addLocalRoutePartition>\n            <routePartition/>\n            <advertiseGloballyIls>f</advertiseGloballyIls>\n          </enterpriseAltNum>\n          <e164AltNum>\n            <numMask/>\n            <isUrgent>f</isUrgent>\n            <addLocalRoutePartition>f</addLocalRoutePartition>\n            <routePartition/>\n            <advertiseGloballyIls>f</advertiseGloballyIls>\n          </e164AltNum>\n          <pstnFailover/>\n          <callControlAgentProfile/>\n          <associatedDevices>\n            <device>SEP00AF1F9C5D7A</device>\n            <device>SEP00AF1F9C5D7B</device>\n          </associatedDevices>\n          <useEnterpriseAltNum>false</useEnterpriseAltNum>\n          <useE164AltNum>false</useE164AltNum>\n          <active>true</active>\n        </line>\n      </return>\n    </ns:getLineResponse>\n  </soapenv:Body>\n</soapenv:Envelope>\n'
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
$$$$$$$$
$$$$$$$$
$$$$$$$$
Traceback (most recent call last):
  File "C:\Program Files (x86)\Python36-32\lib\site-packages\zeep\xsd\valueobjects.py", line 143, in __getattribute__
{
    'return': {
        'line': {
            'pattern': '\\+15553812380',
            'description': 'Captain America',
            'usage': 'Device',
            'routePartitionName': {
                '_value_1': 'Lab',
                'uuid': '{D4452A77-D11C-0810-C506-D09974A022CC}'
            },
            'aarNeighborhoodName': {
                '_value_1': None,


####errors

    return self.__values__[key]
KeyError: 'routePartitionName'

During handling of the above exception, another exception occurred:


Traceback (most recent call last):
  File "C:\Program Files (x86)\Python36-32\lib\site-packages\zeep\xsd\valueobjects.py", line 143, in __getattribute__
    return self.__values__[key]
KeyError: 'routePartitionName'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\t01136.POS\eclipsePython-workspace\AXL-SOAP2\axl-Soap2.py", line 129, in <module>
    test = resp3.routePartitionName
  File "C:\Program Files (x86)\Python36-32\lib\site-packages\zeep\xsd\valueobjects.py", line 146, in __getattribute__
    "%s instance has no attribute '%s'" % (self.__class__.__name__, key)
AttributeError: GetLineRes instance has no attribute 'routePartitionName'

You can clearly see the routePartitionName 'Lab' in the return data, but when I try to grab that data with 

test = resp3.routePartitionName

it doesnt like it?

 

Can anyone spot the trouble? 

 

Thanks

 

 

I figured it out - the correct format is:

S_lRoutPartitNm = phone_get.lines.line[0].dirn.routePartitionName 

For those raw newbies (like me) who might be facing these types of challenges, the methodology I used for figuring it out was to grab and printout a listphone and/or getphone, look at the portion of the return I was looking to variableize, like this:

try:
    resp3 = service.getLine(uuid=uuid_lookup)
#    print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
    print(resp3)
#    print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
    Lphone = resp['return'].phone
except Fault:
  print("$$$$$$$$$$$$   getline failed   $$$$$$$$$$$$$$$")

#returning This:
{
    'return': {
        'line': {
            'pattern': '\\+16513812380',
            'description': 'Captain America',
            'usage': 'Device',
            'routePartitionName': {
                '_value_1': 'Lab',
                'uuid': '{D4452A77-D11C-0810-C506-D09974A022CC}'
            },
            'aarNeighborhoodName': {

Then finally realizing that the { are indicating sub-parameters - which are represented in the variable structures by periods - and trying to walk down the tree from the top - ie

#try this - success
S_lRoutPartitNm = phone_get.lines

#try these - the last one works
S_lRoutPartitNm = phone_get.lines.line
S_lRoutPartitNm = phone_get.lines.line[1]
S_lRoutPartitNm = phone_get.lines.line[0]

finally try this
S_lRoutPartitNm = phone_get.lines.line[0].dirn.routePartitionName 

Then once you get it - its just a matter of getting it in all the right places. - dont forget to keep a sharp eye on case

 

See the Readme also for how to get the Zeep WSDL type dump:

python3 -mzeep schema/AXLAPI.wsdl > wsdl.txt

This can be very helpful in deciphering how Zeep interprets the WSDL

Great Tip! Thanks!

Hello dstaudt.

I am getting the following error when I run resp = service.getLine(uuid='C8E84342-XXXX-AAAA-BBBB-A6E9B3E2F8A8')

=>zeep.exceptions.XMLParseError: Unexpected element 'isAnonymous' 

I know it find the line because as soon as I put in a foo/faux uuid, I get => zeep.exceptions.Fault: Item not valid: The specified Line was not found

 

Thanks

Hello.

I am getting the following error when I run resp = service.getLine(uuid='C8E84342-XXXX-AAAA-BBBB-A6E9B3E2F8A8')

zeep.exceptions.XMLParseError: Unexpected element 'isAnonymous'

I found an article that mentions modifying the AXLsoap.xsd file (as there was some kind of error on that file) but I couldn't find what was suggested in said file.

TIA

It looks like lines/externalPresentationInfo/isAnonymous was added in CUCM 12.5: https://developer.cisco.com/docs/axl/#!axl-developer-guide/new-and-changed-information-for-unified-cm-release-1251

Are you perhaps running against CUCM 12.5+ using an older AXL WSDL, e.g. 11.5?

See the README.md for info on how to swap in/out different AXL versions.

My apologies if my questions seem trivial but I am just starting on this, so quite a newbie on both Python, AXL, et al

I don't know where to find the readme.md but perhaps you can help me with a link. Unsure if the one that you provided above.

Here is the header on my AXL WSDL File (AXLSoap.xsd):

 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:axlapi="http://www.cisco.com/AXL/API/12.5" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://www.cisco.com/AXL/API/12.5" version="12.5">

MY CUCM...Cisco Unified CM Administration, System version: 12.5.1.12900-115

 

I believe I followed (online) instructions to download those AXL WSDL files (schema folder) from the CUCM:

  1. From the CUCM Administration UI, download the 'Cisco AXL Tookit' from Applications / Pluging
  2. Unzip the kit, and navigate to the schema/current folder
  3. Copy the three WSDL files to the schema/ directory of this project: AXLAPI.wsdl, AXLEnums.xsd, AXLSoap.xsd

Thanks for your response and please let me know how I can get past this issue.

FR

Ah, that rang a faint bell

You are correct, in that there is a variance between the AXL WSDL schema and what's returned by the actual AXL implementation.  In essence, the schema says only one of <presentationInfo> or <isAnonymous> should be present, however the implementation returns both.

There are two workarounds I can think of:

1) Set 'strict = False' in the client settings object.  This will cause Zeep to ignore the extraneous element:

# strict=False is not always necessary, but it allows zeep to parse imperfect XML
settings = Settings( strict = False, xml_huge_tree = True )
...
# Create the Zeep client with the specified settings
client = Client( WSDL_FILE, settings = settings, transport = transport,
        plugins = plugin )

2) Perform manual surgery on the AXLSoap.xsd file to change the WSDL to more accurately model the implementation.  This is a bit more fraught, and will potentially need to be done in multiple places (several elements end up use the <externalPresentationInfo> construct), the change is summarized by the attached diff image.  Essentially you'll change the 'choice' begin/end tags to 'sequence' tags:

Screenshot-20210713152241-1931x269.png

 

 

Thanks!...the settings config portion worked...of course I got an error that Settings was not defined, but then a quick search online told me I had to import that from zeep (from zeep import Client, Settings); my code only had import client.

Yeah, you can't add the same line twice until you delete the line on the server. I get around this by just trying to update the line if the add fails. It means I have to have two different xml objects but that was easy to setup

 

    try:
        req = service.addLine(**addline)
        print("Successfully Created phone line")
    except Fault:
        show_history()
        try:
            req = service.updateLine(**updateline)
            print("Successfully updated the existing phone line")
        except Fault:
            show_history()