You are currently viewing Getting Started with Python CUCM AXL API Programming

Getting Started with Python CUCM AXL API Programming

Update:

27th September 2022:
Some errors in the CUCM AXL Schema can cause some get requests to fail (especially getUser) as the Zeep Client receives attributes from the API that aren’t listed in the WSDL file. I’ve updated the code slightly to import the “Settings” module from zeep and to set strict mode to false. This allows the Zeep client to accept attributes that weren’t defined in the AXL Schema explicitly.

 

Update:

19th October 2018:
After several years, my first blog article is still the most popular, however it’s starting to show its age. Firstly it was written using Python 2.7 which at the time seemed to have better 3rd party library support. Python 3 has come a long way since then and is really the only Python you should be using now. Secondly, Python Zeep is a newer, faster and better maintained SOAP library than suds-jurko and after using it for just a short time I find it much better. To put the performance improvement in perspective, on my PC Zeep returns a usable service object in about 5 seconds, whereas suds was taking over 20 seconds (even with a cached WSDL!).

In light of these developments, I decided to update this article. It still contains the exact same content as the previous post, just updated to use Python 3 and Zeep instead.

Introduction

So, after 10 years in the industry I finally got around to creating a blog….. I’m a Network and Unified Comms Engineer (CCNP, from the time when one didn’t have to mention it was in Routing & Switching and in the last 8 or so years also CCIE Voice / Collaboration).

This isn’t supposed to be an in depth tutorial on Python or SOAP APIs. I’m not going to cover how to install Python and other libraries; there’s plenty of other resources for that. This is intended to help other like minded Voice engineers quickly get started without the needless forum trawling and frustration.

Getting Started

First thing you’re going to need:
  • Python (I use v3.6)
  • AXLSQLToolkit (Download from your CUCM Plugins page)
  • zeep (Install via PIP)
  • A CUCM Environment (Installed on a VMWare Workstation is fine. I’m using v11.5 for testing)
  • A bookmark to the Cisco DevNet AXL Schema Reference. You’re going to be here a lot.
 
First, the boilerplate code:
 
# -*- coding: utf-8 -*-
 
from zeep import Client, Settings
from zeep.cache import SqliteCache
from zeep.transports import Transport
from zeep.exceptions import Fault
from zeep.plugins import HistoryPlugin
from requests import Session
from requests.auth import HTTPBasicAuth
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
from lxml import etree
 
 
disable_warnings(InsecureRequestWarning)
 
username = 'administrator'
password = 'ciscopsdt'
# If you're not disabling SSL verification, host should be the FQDN of the server rather than IP
host = '10.10.20.1'
 
wsdl = 'file://C:/Development/Resources/axlsqltoolkit/schema/current/AXLAPI.wsdl'
location = 'https://{host}:8443/axl/'.format(host=host)
binding = "{http://www.cisco.com/AXLAPIService/}AXLAPIBinding"
 
# Create a custom session to disable Certificate verification.
# In production you shouldn't do this, 
# but for testing it saves having to have the certificate in the trusted store.
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(username, password)

settings = Settings(strict=False) transport = Transport(cache=SqliteCache(), session=session, timeout=20) history = HistoryPlugin() client = Client(wsdl=wsdl, transport=transport, plugins=[history], settings=settings) service = client.create_service(binding, location) def show_history(): for item in [history.last_sent, history.last_received]: print(etree.tostring(item["envelope"], encoding="unicode", pretty_print=True))
 
 
Note: There are different AXL Schema versions in incremental steps (i.e. 8.0, 8.5, 9.0, 9.1, 10.0, 10.5, 11.0, 11.5), and you’ll need to be referring to the correct version, otherwise your requests are likely to fail. Here I was using the same axlsqltoolkit that I downloaded directly from the CUCM, so ‘current’ was referring to the most recent version (11.5).

The session object from zeep is what we will be working with to generate SOAP requests without having to deal directly with a SOAP envelope. Instead everything can be done programmatically, dealing with objects and methods instead.

 

Zeep includes the HistoryPlugin which is very useful for troubleshooting. I’ve created a simple helper method “show_history” that will be called in the examples below if there’s a Fault condition. This allows you to see the exact SOAP envelope that was sent and the response from CUCM AXL. This will only show error responses from CUCM (such as that an operation failed due to failed authentication, or an object you’re trying to create already exists, etc).

 

listPhone Request

I’m a firm believer of learn by example, so here is an example listPhone request. I highly recommend using Jupyter Notebooks for testing with Python, as it’s much easier to view large outputs and quickly modify errors as you go. You can get it at http://jupyter.org/
try:
    resp = service.listPhone(searchCriteria={'name': 'SEP001%'}, 
                             returnedTags={'name': '', 'description': ''})
    print(resp)
except Fault:
    show_history()

The listPhone request takes two keyword arguments: searchCriteria and returnedTags. Both of these should be a Python dictionary object containing the key/value pairs that you wish to search for or return respectively. The AXL schema specifies various search criteria such as: ‘name’, ‘description’, ‘protocol’, ‘callingSearchSpaceName’, ‘devicePoolName’ and ‘securityProfileName’. Get used to checking the AXL Schema reference on DevNet to know what you can search based on. The returnedTags includes what attributes you are interested in. The list varies by object, and can be extensive however not all encompassing. For example, there are no returnedTags of ‘line’ or ‘speeddial’. For this you’ll need to use a getPhone request, which requires a unique identifier (either name or uuid).

Here’s an example of what was returned by the above request:

{
    'return': {
        'phone': [
            {
                'name': 'SEP0019E84FDBD1',
                'description': 'SEP0019E84FDBD1',
                'product': None,
                'model': None,
                'class': None,
                'protocol': None,
                'protocolSide': None,
                'callingSearchSpaceName': None,
                'devicePoolName': None,
                'commonDeviceConfigName': None,
                'commonPhoneConfigName': None,
                'networkLocation': None,
                'locationName': None,
                'mediaResourceListName': None,
                'networkHoldMohAudioSourceId': None,
                'userHoldMohAudioSourceId': None,
                'automatedAlternateRoutingCssName': None,
                'aarNeighborhoodName': None,
                'loadInformation': None,
                'traceFlag': None,
                'mlppIndicationStatus': None,
                'preemption': None,
                'useTrustedRelayPoint': None,
                'retryVideoCallAsAudio': None,
                'securityProfileName': None,
                'sipProfileName': None,
                'cgpnTransformationCssName': None,
                'useDevicePoolCgpnTransformCss': None,
                'geoLocationName': None,
                'geoLocationFilterName': None,
                'sendGeoLocation': None,
                'numberOfButtons': None,
                'phoneTemplateName': None,
                'primaryPhoneName': None,
                'ringSettingIdleBlfAudibleAlert': None,
                'ringSettingBusyBlfAudibleAlert': None,
                'userLocale': None,
                'networkLocale': None,
                'idleTimeout': None,
                'authenticationUrl': None,
                'directoryUrl': None,
                'idleUrl': None,
                'informationUrl': None,
                'messagesUrl': None,
                'proxyServerUrl': None,
                'servicesUrl': None,
                'softkeyTemplateName': None,
                'loginUserId': None,
                'defaultProfileName': None,
                'enableExtensionMobility': None,
                'currentProfileName': None,
                'loginTime': None,
                'loginDuration': None,
                'currentConfig': None,
                'singleButtonBarge': None,
                'joinAcrossLines': None,
                'builtInBridgeStatus': None,
                'callInfoPrivacyStatus': None,
                'hlogStatus': None,
                'ownerUserName': None,
                'ignorePresentationIndicators': None,
                'packetCaptureMode': None,
                'packetCaptureDuration': None,
                'subscribeCallingSearchSpaceName': None,
                'rerouteCallingSearchSpaceName': None,
                'allowCtiControlFlag': None,
                'presenceGroupName': None,
                'unattendedPort': None,
                'requireDtmfReception': None,
                'rfc2833Disabled': None,
                'certificateOperation': None,
                'authenticationMode': None,
                'keySize': None,
                'keyOrder': None,
                'ecKeySize': None,
                'authenticationString': None,
                'certificateStatus': None,
                'upgradeFinishTime': None,
                'deviceMobilityMode': None,
                'roamingDevicePoolName': None,
                'remoteDevice': None,
                'dndOption': None,
                'dndRingSetting': None,
                'dndStatus': None,
                'isActive': None,
                'isDualMode': None,
                'mobilityUserIdName': None,
                'phoneSuite': None,
                'phoneServiceDisplay': None,
                'isProtected': None,
                'mtpRequired': None,
                'mtpPreferedCodec': None,
                'dialRulesName': None,
                'sshUserId': None,
                'digestUser': None,
                'outboundCallRollover': None,
                'hotlineDevice': None,
                'secureInformationUrl': None,
                'secureDirectoryUrl': None,
                'secureMessageUrl': None,
                'secureServicesUrl': None,
                'secureAuthenticationUrl': None,
                'secureIdleUrl': None,
                'alwaysUsePrimeLine': None,
                'alwaysUsePrimeLineForVoiceMessage': None,
                'featureControlPolicy': None,
                'deviceTrustMode': None,
                'earlyOfferSupportForVoiceCall': None,
                'requireThirdPartyRegistration': None,
                'blockIncomingCallsWhenRoaming': None,
                'homeNetworkId': None,
                'AllowPresentationSharingUsingBfcp': None,
                'confidentialAccess': None,
                'requireOffPremiseLocation': None,
                'allowiXApplicableMedia': None,
                'enableCallRoutingToRdWhenNoneIsActive': None,
                'ctiid': None,
                'uuid': '{D08E00C5-7B88-7894-83D0-D140018328A4}'
            },
            {
                'name': 'SEP001EBE90E31A',
                'description': '9101',
                'product': None,
                'model': None,
                'class': None,
                'protocol': None,
                'protocolSide': None,
                'callingSearchSpaceName': None,
                'devicePoolName': None,
                'commonDeviceConfigName': None,
                'commonPhoneConfigName': None,
                'networkLocation': None,
                'locationName': None,
                'mediaResourceListName': None,
                'networkHoldMohAudioSourceId': None,
                'userHoldMohAudioSourceId': None,
                'automatedAlternateRoutingCssName': None,
                'aarNeighborhoodName': None,
                'loadInformation': None,
                'traceFlag': None,
                'mlppIndicationStatus': None,
                'preemption': None,
                'useTrustedRelayPoint': None,
                'retryVideoCallAsAudio': None,
                'securityProfileName': None,
                'sipProfileName': None,
                'cgpnTransformationCssName': None,
                'useDevicePoolCgpnTransformCss': None,
                'geoLocationName': None,
                'geoLocationFilterName': None,
                'sendGeoLocation': None,
                'numberOfButtons': None,
                'phoneTemplateName': None,
                'primaryPhoneName': None,
                'ringSettingIdleBlfAudibleAlert': None,
                'ringSettingBusyBlfAudibleAlert': None,
                'userLocale': None,
                'networkLocale': None,
                'idleTimeout': None,
                'authenticationUrl': None,
                'directoryUrl': None,
                'idleUrl': None,
                'informationUrl': None,
                'messagesUrl': None,
                'proxyServerUrl': None,
                'servicesUrl': None,
                'softkeyTemplateName': None,
                'loginUserId': None,
                'defaultProfileName': None,
                'enableExtensionMobility': None,
                'currentProfileName': None,
                'loginTime': None,
                'loginDuration': None,
                'currentConfig': None,
                'singleButtonBarge': None,
                'joinAcrossLines': None,
                'builtInBridgeStatus': None,
                'callInfoPrivacyStatus': None,
                'hlogStatus': None,
                'ownerUserName': None,
                'ignorePresentationIndicators': None,
                'packetCaptureMode': None,
                'packetCaptureDuration': None,
                'subscribeCallingSearchSpaceName': None,
                'rerouteCallingSearchSpaceName': None,
                'allowCtiControlFlag': None,
                'presenceGroupName': None,
                'unattendedPort': None,
                'requireDtmfReception': None,
                'rfc2833Disabled': None,
                'certificateOperation': None,
                'authenticationMode': None,
                'keySize': None,
                'keyOrder': None,
                'ecKeySize': None,
                'authenticationString': None,
                'certificateStatus': None,
                'upgradeFinishTime': None,
                'deviceMobilityMode': None,
                'roamingDevicePoolName': None,
                'remoteDevice': None,
                'dndOption': None,
                'dndRingSetting': None,
                'dndStatus': None,
                'isActive': None,
                'isDualMode': None,
                'mobilityUserIdName': None,
                'phoneSuite': None,
                'phoneServiceDisplay': None,
                'isProtected': None,
                'mtpRequired': None,
                'mtpPreferedCodec': None,
                'dialRulesName': None,
                'sshUserId': None,
                'digestUser': None,
                'outboundCallRollover': None,
                'hotlineDevice': None,
                'secureInformationUrl': None,
                'secureDirectoryUrl': None,
                'secureMessageUrl': None,
                'secureServicesUrl': None,
                'secureAuthenticationUrl': None,
                'secureIdleUrl': None,
                'alwaysUsePrimeLine': None,
                'alwaysUsePrimeLineForVoiceMessage': None,
                'featureControlPolicy': None,
                'deviceTrustMode': None,
                'earlyOfferSupportForVoiceCall': None,
                'requireThirdPartyRegistration': None,
                'blockIncomingCallsWhenRoaming': None,
                'homeNetworkId': None,
                'AllowPresentationSharingUsingBfcp': None,
                'confidentialAccess': None,
                'requireOffPremiseLocation': None,
                'allowiXApplicableMedia': None,
                'enableCallRoutingToRdWhenNoneIsActive': None,
                'ctiid': None,
                'uuid': '{7DB0AE1B-8385-E96B-4D24-86F83FE21543}'
            }
        ]
    },
    'sequence': None
}
Here you can see that despite only requesting certain returnedTags, Python Zeep will return the entire object structure as defined in the WSDL, however any items that weren’t requested as returnedTags will be defined as “None”.
 
For certain Python reserved keywords (i.e. class, return, etc), you need to reference the object as a key (such as resp[‘return’]) rather than with “.” syntax:
phone_list = resp['return'].phone
for phone in phone_list:
    print(phone.name)
 
 
SEP0019E84FDBD1
SEP001EBE90E31A

 getDeviceProfile Request

 

Here’s an example of a getDeviceProfile request. Here we specify a name or uuid.

try:
    resp = service.getDeviceProfile(name='TEST123')
    print(resp)
except Fault:
    show_history()
 
{
    'return': {
        'deviceProfile': {
            'name': 'TEST123',
            'description': 'Test Device Profile',
            'product': 'Cisco 8851',
            'model': 'Cisco 8851',
            'class': 'Device Profile',
            'protocol': 'SIP',
            'protocolSide': 'User',
            'type': 'User Profile',
            'userHoldMohAudioSourceId': None,
            'vendorConfig': None,
            'versionStamp': '{1536766634-5EB18D8C-1AD5-4DEF-93C7-BB0875846F90}',
            'traceFlag': 'false',
            'mlppDomainId': None,
            'mlppIndicationStatus': 'Default',
            'preemption': 'Default',
            'lines': {
                'line': [
                    {
                        'index': 1,
                        'label': 'Test 123',
                        'display': 'Test 123',
                        'dirn': {
                            'pattern': '\+4930555001',
                            'routePartitionName': {
                                '_value_1': None,
                                'uuid': None
                            },
                            'uuid': '{FB5B146F-5805-CF59-5F5E-DC68977C1E83}'
                        },
                        'ringSetting': 'Use System Default',
                        'consecutiveRingSetting': 'Use System Default',
                        'ringSettingIdlePickupAlert': 'Use System Default',
                        'ringSettingActivePickupAlert': 'Use System Default',
                        'displayAscii': 'Test 123',
                        'e164Mask': None,
                        'dialPlanWizardId': None,
                        'mwlPolicy': 'Use System Policy',
                        'maxNumCalls': 6,
                        'busyTrigger': 2,
                        'callInfoDisplay': {
                            'callerName': 'false',
                            'callerNumber': 'false',
                            'redirectedNumber': 'false',
                            'dialedNumber': 'false'
                        },
                        'recordingProfileName': {
                            '_value_1': None,
                            'uuid': None
                        },
                        'monitoringCssName': {
                            '_value_1': None,
                            'uuid': None
                        },
                        'recordingFlag': 'Call Recording Disabled',
                        'audibleMwi': 'Default',
                        'speedDial': None,
                        'partitionUsage': 'General',
                        'associatedEndusers': None,
                        'missedCallLogging': 'true',
                        'recordingMediaSource': 'Gateway Preferred',
                        'ctiid': None,
                        'uuid': '{472FAD42-5D96-02FB-C723-0D00A292054B}'
                    }
                ],
                'lineIdentifier': None
            },
            'numberOfButtons': 10,
            'phoneTemplateName': {
                '_value_1': 'Standard 8851 SIP',
                'uuid': '{7227EFC0-2769-4B6B-A25B-E76F909DE019}'
            },
            'speeddials': None,
            'busyLampFields': None,
            'blfDirectedCallParks': None,
            'addOnModules': None,
            'userLocale': None,
            'defaultProfileName': 'NullIdValue',
            'currentProfileName': {
                '_value_1': None,
                'uuid': None
            },
            'loginTime': None,
            'loginDuration': None,
            'singleButtonBarge': 'Default',
            'joinAcrossLines': 'Default',
            'loginUserId': {
                '_value_1': None,
                'uuid': None
            },
            'ignorePresentationIndicators': 'false',
            'dndOption': 'Use Common Phone Profile Setting',
            'dndRingSetting': None,
            'dndStatus': 'false',
            'emccCallingSearchSpace': {
                '_value_1': None,
                'uuid': None
            },
            'alwaysUsePrimeLine': 'Default',
            'alwaysUsePrimeLineForVoiceMessage': 'Default',
            'softkeyTemplateName': {
                '_value_1': None,
                'uuid': None
            },
            'callInfoPrivacyStatus': 'Default',
            'currentConfig': {
                'userHoldMohAudioSourceId': None,
                'phoneTemplateName': {
                    '_value_1': None,
                    'uuid': None
                },
                'mlppDomainId': None,
                'mlppIndicationStatus': None,
                'preemption': None,
                'softkeyTemplateName': {
                    '_value_1': None,
                    'uuid': None
                },
                'ignorePresentationIndicators': None,
                'singleButtonBarge': None,
                'joinAcrossLines': None,
                'callInfoPrivacyStatus': None,
                'dndStatus': None,
                'dndRingSetting': None,
                'dndOption': None,
                'alwaysUsePrimeLine': None,
                'alwaysUsePrimeLineForVoiceMessage': None,
                'emccCallingSearchSpaceName': {
                    '_value_1': None,
                    'uuid': None
                },
                'deviceName': None,
                'model': None,
                'product': None,
                'deviceProtocol': None,
                'class': None,
                'addressMode': None,
                'allowAutoConfig': None,
                'remoteSrstOption': None,
                'remoteSrstIp': None,
                'remoteSrstPort': None,
                'remoteSipSrstIp': None,
                'remoteSipSrstPort': None,
                'geolocationInfo': None,
                'remoteLocationName': None
            },
            'services': None,
            'featureControlPolicy': {
                '_value_1': None,
                'uuid': None
            },
            'ctiid': 39,
            'uuid': '{386C61E6-F06B-94FB-7E78-DB771172B11F}'
        }
    },
    'sequence': None
}
As you can see, the returned object includes every attribute of the Device Profile. Unfortunately the returned object cannot simply be modified and passed back in an updateDeviceProfile request as Zeep expects keyword arguments for those types of requests and won’t accept a RDeviceProfile object. Even if you serialize the object into a dict and pass it to an updateDeviceProfile as **kwargs it will still fail as there are extra attributes that are presented in a getDeviceProfile that aren’t accepted in an updateDeviceProfile. In practise I haven’t found this to be a huge limitation.

Moving on, here we can get some more detail, such as the directory number assigned to the profile.

dp = resp['return'].deviceProfile
line_appearances = dp.lines.line
print(line_appearances[0])
 
{
    'index': 1,
    'label': 'Test 123',
    'display': 'Test 123',
    'dirn': {
        'pattern': '\+4930555001',
        'routePartitionName': {
            '_value_1': None,
            'uuid': None
        },
        'uuid': '{FB5B146F-5805-CF59-5F5E-DC68977C1E83}'
    },
    'ringSetting': 'Use System Default',
    'consecutiveRingSetting': 'Use System Default',
    'ringSettingIdlePickupAlert': 'Use System Default',
    'ringSettingActivePickupAlert': 'Use System Default',
    'displayAscii': 'Test 123',
    'e164Mask': None,
    'dialPlanWizardId': None,
    'mwlPolicy': 'Use System Policy',
    'maxNumCalls': 6,
    'busyTrigger': 2,
    'callInfoDisplay': {
        'callerName': 'false',
        'callerNumber': 'false',
        'redirectedNumber': 'false',
        'dialedNumber': 'false'
    },
    'recordingProfileName': {
        '_value_1': None,
        'uuid': None
    },
    'monitoringCssName': {
        '_value_1': None,
        'uuid': None
    },
    'recordingFlag': 'Call Recording Disabled',
    'audibleMwi': 'Default',
    'speedDial': None,
    'partitionUsage': 'General',
    'associatedEndusers': None,
    'missedCallLogging': 'true',
    'recordingMediaSource': 'Gateway Preferred',
    'ctiid': None,
    'uuid': '{472FAD42-5D96-02FB-C723-0D00A292054B}'
}

 

addLine Request

Ok, now on to actually adding some things. Here there’s a few options with how you can go about it. You can form the request manually like the following:
 
try:
    resp  = service.addLine(line={'pattern': '10008', 'usage': 'Device'})
    print(resp)
except Fault:
    show_history()
 
{
    'return': '{9DF407FE-8AD9-93B5-63DE-29E5B03E3A21}',
    'sequence': None
}

If your add was successful, you get a response with the UUID of the object in the reply. When adding items you need to refer to the AXL Schema to determine which elements are mandatory. For a line, the “pattern” is mandatory (the <None>  partition is assumed), and also Zeep will throw an Exception if you exclude the “usage” attribute. This determines if the line is for a Device or for Intercom.

If you leave out a mandatory attribute, you’ll get an Exception as zeep won’t even pass the request if there’s a mandatory attribute missing.
try:
    resp  = service.addLine(line={'description': 'Test', 'usage': 'Device'})
    print(resp)
except Fault:
    show_history() 

# ** output omitted **
 
ValidationError: Missing element pattern (addLine.line.pattern)

addDeviceProfile Request

Now, onto a more object oriented way. Here you can use the suds “factory.create()” method, to create an object based on the WSDL, modify the necessary attributes, and then pass that object to the add method. I could have used this for creating a directory number, but wanted to demonstrate both ways. To get the specific object type, refer to the AXL Schema.

Here we configure the mandatory attributes:

factory = client.type_factory('ns0')
dp = factory.XDeviceProfile(name="SEP001122334455")
dp.name = "NAME"
dp.description = "Description"
dp.protocol = "SIP"
dp.product = "Cisco 7965"
dp.protocolSide = "User"
dp.phoneTemplateName = "Standard 7965 SIP"
dp['class'] = "Device Profile"
 
try: 
    resp = service.addDeviceProfile(dp)
    print(resp)
except Fault:
    show_history()
 
{
    'return': '{530225C8-92EC-E17E-86B6-277FA280F624}',
    'sequence': None
}

 Summary

So, that’s it for this post. I’ve written a followup post to this, with a couple of practical examples. As I haven’t updated that post to use Python Zeep, it still references the more outdated Python Suds, but the principals should be the same.

You can find it here: CUCM AXL Python Programming – The next steps

 

This Post Has 5 Comments

  1. Mitch

    This comment has been removed by the author.

  2. Jonathan Els

    Hey Paul T

    This is a great article and helped me a lot getting this set up!

    Just one piece of criticism/a suggestion for you…

    Perhaps check this out:

    http://www.problemofnetwork.com/2015/05/using-callmanager-apis-for-fun-and.html

    With this code, my output is a suds object, not a tuple, meaning that I don't need the hardcoded tuple indexing that you're using here:

    >>> phone_list = resp[1]['return'].phone
    >>>
    >>> phone_list[0].name

    Regards,
    Jonathan

  3. Paul T

    Hey, glad it could help 🙂

    I had a quick glance through though the link and makes me think that might have been useful for me when starting out ;). I guess Google page rankings don't always favour the exact content you're looking for. It seems the author didn't have the same issues I had with suds (thus why i used suds-jurko and the ImportDoctor).

    I'm not quite sure which specific section you mean regarding the output being an object though. The phone_list is just a list or tuple of phone objects which you could iterate through. I'm sure there's definitely better ways than what I'm doing though, as I'm still learning.

    I really wish Cisco would switch to a REST API 🙁

  4. tity

    Hi Paul,
    I python and cucm-axl beginner.
    I can listline and add line into CUCM. But I can't update line on cucm.

    client.service.updateLine(
    pattern='3001',
    routePartitionName={'value' : "P_Internal", '_uuid' : "{0DA76261-2A84-B998-1BE7-9BD00FFC2E51}"},
    newPattern='3014')

    I got error

    3014

    Traceback (most recent call last):
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudstransporthttp.py", line 78, in send
    fp = self.u2open(u2request)
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudstransporthttp.py", line 119, in u2open
    return url.open(u2request, timeout=tm)
    File "C:UsersTityAppDataLocalProgramsPythonPython35liburllibrequest.py", line 472, in open
    response = meth(req, response)
    File "C:UsersTityAppDataLocalProgramsPythonPython35liburllibrequest.py", line 582, in http_response
    'http', request, response, code, msg, hdrs)
    File "C:UsersTityAppDataLocalProgramsPythonPython35liburllibrequest.py", line 510, in error
    return self._call_chain(*args)
    File "C:UsersTityAppDataLocalProgramsPythonPython35liburllibrequest.py", line 444, in _call_chain
    result = func(*args)
    File "C:UsersTityAppDataLocalProgramsPythonPython35liburllibrequest.py", line 590, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
    urllib.error.HTTPError: HTTP Error 500: Internal Server Error

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudsclient.py", line 652, in send
    reply = transport.send(request)
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudstransporthttp.py", line 178, in send
    return HttpTransport.send(self, request)
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudstransporthttp.py", line 86, in send
    raise TransportError(e.msg, e.code, e.fp)
    suds.transport.TransportError: Internal Server Error

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
    File "C:/Users/Tity/PycharmProjects/begin01/CUCM_UpdateLine.py", line 31, in
    newPattern='3014')
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudsclient.py", line 559, in __call__
    return client.invoke(args, kwargs)
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudsclient.py", line 618, in invoke
    result = self.send(soapenv)
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudsclient.py", line 664, in send
    result = self.failed(binding, e)
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudsclient.py", line 720, in failed
    r, p = binding.get_fault(reply)
    File "C:UsersTityAppDataLocalProgramsPythonPython35libsite-packagessudsbindingsbinding.py", line 267, in get_fault
    raise WebFault(p, faultroot)
    suds.WebFault: b"Server raised fault: 'Directory Number not found'"

  5. Paul T

    The last line gives the most information – "Directory Number not Found". You probably don't need to specify both the routePartitionName and the __uuid in your query (See the structure of the request here:https://developer.cisco.com/media/axl-schema-10-0/AXLSoap_updateLine.html#LinkECA ), but rather JUST the _uuid, OR the pattern AND the routePartitionName.

    Perhaps try giving just the existing pattern and routePartitionName (since that is enough to uniquely identify it), then the newPattern and if relevant the newRoutePartitionName.

    i.e.
    client.service.updateLine(
    pattern='3001',
    routePartitionName="P_Internal",
    newPattern='3014')

    You can also look at turning on the logging for suds-jurko, then you can see the actual SOAP message it generates to see if anything looks out of place.

    I'm on holiday atm so couldn't test this myself or check some of the existing queries I've done in the past… with some of the queries the structure of the request with suds-jurko can get a bit funky, so it sometimes takes a bit of playing around.

    Let me know if you still don't get it working and I can take a look at my previous code in a week or so to see how I've done it in the past.

Comments are closed.