cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
7358
Views
12
Helpful
13
Replies

Python script for display registered phones from CUCM ver 11.5 - TypeError: string indices must be integers

rajesh.kumar
Level 4
Level 4

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

 

13 Replies 13

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.

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)

 

 

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?

Thanks, I will cross verify. it could be firewall issue.
Is there any limitation of only 1000 IP Phones can be retrieved ? Currently I don't have setup with more than 1000 IP Phones.

Seems like something else is wrong. I can access this link through browser. Script is giving error. But same script works perfectly with CUCM version 11.5
https://x.x.x.x:8443/realtimeservice2/services/RISService70?wsdl

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)

Hi credentials are correct. Cross verified.

Here is my observation. Is this could be causing the issue ?
for CUCM version 12.5
inside https://<cucmIP>:8443/realtimeservice2/services/RISService70?wsdl
I have below entry.
<wsdlsoap:address location="https://localhost:8443/realtimeservice2/services/RISService70"/>

but for CUCM 11.5
localhost is replaced with specific IP address. Is that could be causing the issue ?

Hi
for CUCM version 12.5
inside https://<cucmIP>:8443/realtimeservice2/services/RISService70?wsdl
I have below entry.
<wsdlsoap:address location="https://localhost:8443/realtimeservice2/services/RISService70"/>

but for CUCM 11.5
localhost is replaced with specific IP address. Is that could be causing the issue ?

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/

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

This fixed my issue with 12.5!!!

Same script was working with 11.5 ...... great fix jsut wish I found it sooner!

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')

jefryarch
Level 1
Level 1

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.