06-21-2019 01:14 AM
Here is my Python script for display registered IP Phones details from Cisco CallManager 11.5. I am facing one issue in displaying output in customized format.
from zeep import Client
from zeep.cache import SqliteCache
from zeep.transports import Transport
from zeep.plugins import HistoryPlugin
from requests import Session
from requests.auth import HTTPBasicAuth
from lxml import etree
import urllib3
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
username = 'xxxx'
password = 'xxxx'
wsdl = 'https://x.x.x.x:8443/realtimeservice2/services/RISService70?wsdl'
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(username, password)
transport = Transport(cache=SqliteCache(), session=session, timeout=20)
history = HistoryPlugin()
client = Client(wsdl=wsdl, transport=transport, plugins=[history])
factory = client.type_factory('ns0')
macs = ['*'] #'*' for all
item=[]
for mac in macs:
item.append(factory.SelectItem(Item=mac))
Item = factory.ArrayOfSelectItem(item)
stateInfo = ''
criteria = factory.CmSelectionCriteria(
MaxReturnedDevices = 1000,
DeviceClass='Phone',
Model=255, #255 for all
Status='Registered',
NodeName='',
SelectBy='Name',
SelectItems=Item,
Protocol='Any',
DownloadStatus='Any'
)
result = client.service.selectCmDevice(stateInfo, criteria)
for node in (result['SelectCmDeviceResult']['CmNodes']):
for device in node['CmDevices']:
print (device['Name'], device['IpAddress'], device['DirNumber'], device['Description'])
If I just print (result) I am getting output as below output, I want to display output in proper way, onlt name, IP address, directory number and description
But while adding "for device in node" I am getting error on this line as below;
for device in node['CmDevices']:
error is:
Traceback (most recent call last):
File "phone2.py", line 40, in <module>
for device in node['CmDevices']:
TypeError: string indices must be integers
Pls. advice why TypeError: string indices must be integers
Script Output from Cisco CallManager, while running the script with only print (result)
{
'SelectCmDeviceResult': {
'TotalDevicesFound': 43,
'CmNodes': {
'item': [
{
'ReturnCode': 'NotFound',
'Name': '10.10.161.10',
'NoChange': False,
'CmDevices': {
'item': []
}
},
{
'ReturnCode': 'Ok',
'Name': '10.10.161.11',
'NoChange': False,
'CmDevices': {
'item': [
{
'Name': 'SEP009AD2D3E9C0',
'DirNumber': '7010-Registered',
'DeviceClass': 'Phone',
'Model': 688,
'Product': 573,
'BoxProduct': 0,
'Httpd': 'Yes',
'RegistrationAttempts': 1,
'IsCtiControllable': True,
'LoginUserId': None,
'Status': 'Registered',
'StatusReason': 0,
'PerfMonObject': 2,
'DChannel': 0,
'Description': 'SEP009AD2D3E9C0',
'H323Trunk': {
'ConfigName': None,
'TechPrefix': None,
'Zone': None,
'RemoteCmServer1': None,
'RemoteCmServer2': None,
'RemoteCmServer3': None,
'AltGkList': None,
'ActiveGk': None,
'CallSignalAddr': None,
'RasAddr': None
},
'TimeStamp': 1561098640,
'Protocol': 'SIP',
'NumOfLines': 1,
'LinesStatus': {
'item': [
{
'DirectoryNumber': '7010',
'Status': 'Registered'
}
]
},
'ActiveLoadID': 'ce-9.3.0-d31e4c18-2017-11-21',
'InactiveLoadID': None,
'DownloadStatus': 'Unknown',
'DownloadFailureReason': None,
'DownloadServer': None,
'IPAddress': {
'item': [
{
'IP': '10.10.161.187',
'IPAddrType': 'ipv4',
'Attribute': 'Unknown'
}
]
}
},
{
'Name': 'SEP00A3D15CBB31',
'DirNumber': '7020-Registered',
'DeviceClass': 'Phone',
'Model': 690,
'Product': 575,
'BoxProduct': 0,
'Httpd': 'Yes',
'RegistrationAttempts': 1,
'IsCtiControllable': True,
'LoginUserId': None,
'Status': 'Registered',
'StatusReason': 0,
'PerfMonObject': 2,
'DChannel': 0,
'Description': 'Africa MR',
'H323Trunk': {
'ConfigName': None,
'TechPrefix': None,
'Zone': None,
'RemoteCmServer1': None,
'RemoteCmServer2': None,
'RemoteCmServer3': None,
'AltGkList': None,
'ActiveGk': None,
'CallSignalAddr': None,
'RasAddr': None
},
Traceback (most recent call last):
File "phone2.py", line 40, in <module>
for device in node['CmDevices']:
TypeError: string indices must be integers
06-22-2019 08:31 AM - edited 06-22-2019 09:18 AM
What is the exact data structure your script is storing in node?
Try with this and share the output:
import pprint
. . .
result = client.service.selectCmDevice(stateInfo, criteria)
for node in (result['SelectCmDeviceResult']['CmNodes']):
pprint.pprint(node)
This should return the output in a readable format.
06-22-2019 09:50 AM
Dear Hector
I have rectified it by modifying the script print part as below. Now script is working fine.
result = client.service.selectCmDevice(stateInfo, criteria)
for node in (result['SelectCmDeviceResult']['CmNodes']['item']):
for device in node['CmDevices']['item']:
ipaddresses = device['IPAddress']
ipaddress = ipaddresses['item'][0]['IP'] if ipaddresses else ''
print (device['Name'], ipaddress, device['DirNumber'], device['Model'], device['Protocol'], device['Description'])
However, this entire script works fine with Cisco CallManager version 11.5. But when I run this script on CallManager ver 12.5. I get error.
$ python phone2-m.py
Traceback (most recent call last):
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\connection.py", line 159, in _new_conn
(self._dns_host, self.port), self.timeout, **extra_kw)
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\util\connection.py", line 80, in create_connection
raise err
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\util\connection.py", line 70, in create_connection
sock.connect(sa)
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\connectionpool.py", line 600, in urlopen
chunked=chunked)
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\connectionpool.py", line 343, in _make_request
self._validate_conn(conn)
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\connectionpool.py", line 839, in _validate_conn
conn.connect()
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\connection.py", line 301, in connect
conn = self._new_conn()
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\connection.py", line 168, in _new_conn
self, "Failed to establish a new connection: %s" % e)
urllib3.exceptions.NewConnectionError: <urllib3.connection.VerifiedHTTPSConnection object at 0x03A34ED0>: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\code\dnav3-code\venv\lib\site-packages\requests\adapters.py", line 449, in send
timeout=timeout
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\connectionpool.py", line 638, in urlopen
_stacktrace=sys.exc_info()[2])
File "D:\code\dnav3-code\venv\lib\site-packages\urllib3\util\retry.py", line 399, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='localhost', port=8443): Max retries exceeded with url: /realtimeservice2/services/RISService70 (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x03A34ED0>: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "phone2-moh.py", line 38, in <module>
result = client.service.selectCmDevice(stateInfo, criteria)
File "D:\code\dnav3-code\venv\lib\site-packages\zeep\proxy.py", line 45, in __call__
kwargs,
File "D:\code\dnav3-code\venv\lib\site-packages\zeep\wsdl\bindings\soap.py", line 122, in send
response = client.transport.post_xml(options["address"], envelope, http_headers)
File "D:\code\dnav3-code\venv\lib\site-packages\zeep\transports.py", line 95, in post_xml
return self.post(address, message, headers)
File "D:\code\dnav3-code\venv\lib\site-packages\zeep\transports.py", line 62, in post
address, data=message, headers=headers, timeout=self.operation_timeout
File "D:\code\dnav3-code\venv\lib\site-packages\requests\sessions.py", line 572, in post
return self.request('POST', url, data=data, json=json, **kwargs)
File "D:\code\dnav3-code\venv\lib\site-packages\requests\sessions.py", line 524, in request
resp = self.send(prep, **send_kwargs)
File "D:\code\dnav3-code\venv\lib\site-packages\requests\sessions.py", line 637, in send
r = adapter.send(request, **kwargs)
File "D:\code\dnav3-code\venv\lib\site-packages\requests\adapters.py", line 516, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='localhost', port=8443): Max retries exceeded with url: /realtimeservice2/services/RISService70 (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x03A34ED0>: Failed to establish a new connection: [WinError 10061] No connection could be made because the target machine actively refused it'))
(venv)
06-22-2019 10:14 AM - edited 06-22-2019 10:15 AM
First problem was related to the way you were parsing the data in the "node" variable.
But now for your second problem, it looks your script cannot even connect to your instance of CallManager running 12.5 on TCP port 8443.
- Is there a firewall or similar blocking this connectivity from your PC to your CallManager running 12.5?
- Is your CallManager running 12.5 really listening on TCP 8443?
- Is your CallManager running 12.5 configured to refuse incoming connections from certain IPs?
06-23-2019 02:18 AM
06-23-2019 02:26 AM
06-23-2019 09:29 AM
If it is shown in your WebBrowser on the same PC you are running the script from then may be something with the script itself... are the username and password correct?
username = 'xxxx' password = 'xxxx' session.auth = HTTPBasicAuth(username, password)
06-23-2019 12:02 PM
06-23-2019 03:14 AM
06-26-2019 08:32 AM
When you create the service object, Zeep allows you to modify the target location:
client = Client( WSDL_FILE, settings = settings, transport = transport, plugins = plugin ) service = client.create_service( '{http://schemas.cisco.com/ast/soap}RisBinding', 'https://{cucm}:8443/realtimeservice2/services/RISService70'.format( cucm = creds.CUCM_ADDRESS ))
This construction will also allow you to query multiple CUCM nodes without downloading the WSDL from each.
See this sample project which I've updated using the above - seems to work for 11.5/12.5: https://github.com/CiscoDevNet/serviceability-python-zeep-samples/
02-17-2020 09:36 AM - edited 05-28-2020 08:00 PM
Hi Rajesh,
i am writing a python script with version 12.5 recently and encountering the same issue as you, here is how i resolved it :
1. Use any browser to access 'https://x.x.x.x:8443/realtimeservice2/services/RISService70?wsdl'
the x.x.x.x is your CUCM IP address, and save the output to your python server as text file, lets say: RISService70-125.wsdl, and delete the first line "This XML file...."
in the bottom of the file, you will find
<wsdlsoap:address location="https://localhost:8443/realtimeservice2/services/RISService70"/>
change it to :
<wsdlsoap:address location="https://x.x.x.x:8443/realtimeservice2/services/RISService70"/>
the x.x.x.x is your CUCM IP address
2. Change the wsdl path in your previous script:
from
wsdl = 'https://x.x.x.x:8443/realtimeservice2/services/RISService70?wsdl'
to
wsdl = 'file:///PATH/RISService70-125.wsdl'
the PATH is where the file locates in your python server
let me know if it works for your case, :)
-Eddie Lu
07-28-2021 04:44 PM
This fixed my issue with 12.5!!!
Same script was working with 11.5 ...... great fix jsut wish I found it sooner!
09-01-2023 11:15 AM - edited 09-01-2023 01:35 PM
Thanks, eddie.lue, and all of you guys.
I want to share this version that exports the Name, Description, Directory Number, Protocol, Status, IP, Model, Firmware, UnifiedCM in a CSV file.
Note: You need to still do the eddie.lue steps mentioned above.
from zeep import Client
from zeep.cache import SqliteCache
from zeep.transports import Transport
from zeep.plugins import HistoryPlugin
from requests import Session
from requests.auth import HTTPBasicAuth
from lxml import etree
import urllib3
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
from pprint import pprint
import pandas as pd
import datetime
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
username = 'username'
password = 'password'
wsdl = 'file:///PATH/RISService70-125.wsdl'
session = Session()
session.verify = False
session.auth = HTTPBasicAuth(username, password)
transport = Transport(cache=SqliteCache(), session=session, timeout=20)
history = HistoryPlugin()
client = Client(wsdl=wsdl, transport=transport, plugins=[history])
factory = client.type_factory('ns0')
macs = ['*'] #'*' for all
item=[]
for mac in macs:
item.append(factory.SelectItem(Item=mac))
Item = factory.ArrayOfSelectItem(item)
stateInfo = ''
criteria = factory.CmSelectionCriteria(
MaxReturnedDevices = 2000,
DeviceClass='Any',
Model=255, #255 for all
Status='Any',
NodeName='',
SelectBy='Name',
SelectItems=Item,
Protocol='Any',
DownloadStatus='Any'
)
result = client.service.selectCmDevice(stateInfo, criteria)
d = []
for node in (result['SelectCmDeviceResult']['CmNodes']['item']):
for device in node['CmDevices']['item']:
ipaddresses = device['IPAddress']
ipaddress = ipaddresses['item'][0]['IP'] if ipaddresses else ''
DirNumber = str(device['DirNumber'])
DirNumber = DirNumber.replace('-Registered', '')
DirNumber = DirNumber.replace('-UnRegistered', '')
d.append(
{
'Name': device['Name'],
'Description': device['Description'],
'Directory Number': DirNumber,
'Protocol': device['Protocol'],
'Status':device['Status'],
'IP': ipaddress,
'Model':device['DeviceClass'],
'Firmware':device['ActiveLoadID'],
'UnifiedCM':node['Name']
}
)
dataframe = pd.DataFrame(d)
now = str(datetime.datetime.now())
dataframe.to_csv(".\\CUCMPhoneStatus "+now.replace(':', '.')+".csv", index=False, header=True, mode='w')
01-03-2021 10:33 PM
TypeError: means that you are trying to perform an operation on a value whose type is not compatible with that operation. If you are accessing items from a dictionary , make sure that you are accessing the dictionary itself and not a key in the dictionary. TypeError: string indices must be integers has been caused because you are trying to access values from dictionary using string indices instead of integer.
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