02-25-2020 09:06 AM
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
Solved! Go to Solution.
04-14-2020 07:21 AM
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()
02-25-2020 09:24 AM
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
02-26-2020 07:51 AM
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??
02-26-2020 08:19 AM
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...
02-29-2020 04:28 PM
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
03-02-2020 05:33 PM
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
03-03-2020 09:10 AM
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
03-04-2020 07:38 PM
Great Tip! Thanks!
07-12-2021 12:42 PM
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
07-12-2021 12:32 PM
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
07-13-2021 10:29 AM
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.
07-13-2021 12:24 PM
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:
Thanks for your response and please let me know how I can get past this issue.
FR
07-13-2021 01:23 PM
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:
07-14-2021 12:42 PM
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.
04-14-2020 07:21 AM
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()
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide