01-12-2018 05:10 PM
By default, the CUCM Serviceability API returns a maximum of 1000 devices.
How can I get more than that?
I am modifying Alexey Smirnov's Python script found here: https://communities.cisco.com/docs/DOC-59446
There is a single statement "response=requests.post('https://' + CMserver + ':8443/......" that returns 1000 results (as expected).
I know the AXL API has a SKIP/FIRST feature in the requests that allows you to get the next group of results, but I can't find anything similar in Serviceability. I have played around with MaxReturnedDevices, but that only limits the number to less than 1000.
Here is my code, it works great in Python 3.6 with CUCM 10.5.2. It spits the results into a CSV file, the problem is I have around 7000 phones, and the script quits at 1000. Please note that I am a beginner at scripting in Python.
thanks, Randy
.....................................................
#works in Python 3.6
import requests
import csv
import xml.etree.ElementTree
from requests.auth import HTTPBasicAuth
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
#Ask user some questions
fileName = input('Enter the CSV filename: ')
CMserver= input('Enter Publisher IP: ')
serv_user= input('Enter AXL Username: ')
serv_pass= input('Enter AXL User Password: ')
model='255' #255 returns all phone models
#create and open your CSV file
outputFile = open(fileName + '.csv', 'w', newline='')
outputWriter = csv.writer(outputFile)
outputWriter.writerow(["Host Name", "DN", "IP Address", "Status"]) #create the header row
raw_xml = """<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:ns3="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns0="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:ns1="http://schemas.cisco.com/ast/soap/"
xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header/>
<ns2:Body>
<ns1:SelectCmDevice>
<StateInfo xsi:type="ns3:string"></StateInfo>
<CmSelectionCriteria xsi:type="ns1:CmSelectionCriteria">
<ns1:Class xsi:type="ns3:string">Phone</ns1:Class>
<ns1:Model xsi:type="ns3:unsignedInt">{0}</ns1:Model>
<ns1:SelectBy xsi:type="ns3:string">Name</ns1:SelectBy>
</CmSelectionCriteria>
</ns1:SelectCmDevice>
</ns2:Body>
</SOAP-ENV:Envelope>""".format(model)
headers={'SOAPAction': '"http://schemas.cisco.com/ast/soap/action/#RisPort#SelectCmDevice"',
'Content-Type': 'text/xml; charset=utf-8',
'Content-type': 'text/xml; charset=utf-8',
'Soapaction': '"http://schemas.cisco.com/ast/soap/action/#RisPort#SelectCmDevice"'}
response=requests.post('https://' + CMserver + ':8443/realtimeservice/services/RisPort',data=raw_xml,headers=headers, auth=HTTPBasicAuth(serv_user, serv_pass),verify=False)
tree = xml.etree.ElementTree.fromstring(response.text)
CmNodes = tree.find("{http://schemas.xmlsoap.org/soap/envelope/}Body").find("{http://schemas.cisco.com/ast/soap/}SelectCmDeviceResponse").find("SelectCmDeviceResult").find("CmNodes")
for node in CmNodes:
for devs in node.find("CmDevices"):
# Now write the data to a row in yor CSV
outputWriter.writerow([devs.find('Name').text, devs.find('DirNumber').text, devs.find('IpAddress').text, devs.find('Status').text])
# When you have iterated through all rows, close the file
outputFile.close()
print("All Done")
06-24-2019 02:26 AM
My advice with this would be to approach your task a bit differently and instead explicitly request every individual phone.
You could for instance with AXL perform a listPhone with a searchCriteria of '%' to get every single device on the cluster. Then you can save the <name> into a list.
Once you have this, you can build a SOAP Query to RisPort70 API, specifically requesting each name, up to 1000, then get the results. Then perform the next 1000, and so on.
Here's a simple example to split up a list into desired chunks, where phone_list is a list that contains ALL phones:
As a List Comprehension:
split_phone_list = [phone_list[x:x+1000] for x in range (0, len(phone_list), 1000)]
This will give you a single list that contains sub-lists containing no more than 1000 items.
Then you can loop through the outer list, and for each iteration make a single RisPort70 query using the names from the inner list.
Hope this helps.... I can tell you it will be a lot easier for you if you use a SOAP library like python-zeep so that you don't have to deal with the raw SOAP envelope. I did a blog post on this a while back with the Serviceability API: https://paultursan.com/2018/12/getting-cucm-real-time-data-via-risport70-with-python-and-zeep-cisco-serviceability-api/
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