Serviceability Control Center

Recently, I’ve decided to try out CAXL IM&Presence API (https://developer.cisco.com/site/jabber-websdk/overview/overview/) and integrate a Web chat with Jabber MUCs (chat conferences). And it turns out that XCP Web connection manager which serves BOSH interface for CAXL (or jabberwerx) can’t stand more than 100 concurrent connections. This service just went to Stopped state.

While troubleshooting that with UC serviceability web interface on CUCM (like going to Cisco unified Serviceability ->  Tools -> Control center Feature services ot Network services -> choosing a node and it takes quite some time to fetch the data) I decided to write a simple GUI for this. I’ve based my server on a API’s description from here https://developer.cisco.com/site/sxml/discover/overview/service-control/.

The source is accessible from my github https://github.com/smirnov-am/cucm_srv_cc_api.

Installation should be easy: on a server with python installed, use pip to get flask and apscheduler modules and run the script. Open a browser and enter your server IP and enter srv_mon/srv_mon when it asks for credentials.

On configuration enter your CUCM and IM&P node IPs and hit Save&Run. The UCM and IMP pages should populate with service’s states:

 

cc

Services that are activated and not running come first, started services are just highlighted with green, inaccessible nodes and inactivated services are grey and can be found in the end of the list.

I’m going to invest some time into it later and add service stop/start/restart capabilities to it.

It looks like you can get the same info from RTMT or PrimeCollaboration which is free if you got CUWL Pro licence. But first one is slow and the latter is very greedy for computing resources and I find my solution much more helpful when debugging service states.

Monitoring device registration with CUCM Serviceability AXL API

Recently I started to receive more and more complaints from my users that my Cisco video codecs are not working. The problem was that these same users had unplugged ethernet cords from the codecs so they lost registration with CUCM. So I decided to create some tool to monitor registration status of video endpoints and possibly 7937 conference phones (they’ve got unplugged too).

I decided that CUCM Serviceability API (https://developer.cisco.com/site/collaboration/management/uc-manager-serviceability/overview/) would do.
1) Let’s install suds module (and we will need python 2.7.9 with ssl module too)

cd ~/Downloads
sudo wget https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
sudo python -m pip install suds
cd ~/
vi srv_xml_api.py

2) Inside srv_xml_api.py let’s import only necessary parts:

import sslimport urllib2from suds.xsd.doctor 
import Importfrom suds.xsd.doctor 
import ImportDoctorfrom suds.client 
import Clientfrom suds.transport.https 
import HttpAuthenticatedfrom datetime 
import datetime, timedelta

3) Let’s also define global variable MODELS – a dictionary with device’s model id as it appears in CUCM database and its description:

MODELS={'626':'Cisco TelePresence SX20',        
        '682':  'Cisco TelePresence SX10',
        '608':  'Cisco TelePresence Codec C40'}

4) We will also need path to CUCM Serviceability API, and application user credentials to access it.

SRV_CMSERVER='192.168.0.1' #IP of CUCM
SRV_axl_port='8443'
SRV_user='srv_api_user'
SRV_passwd='****'
SRV_wsdl='https://'+SRV_CMSERVER+':'+SRV_axl_port+'/realtimeservice/services/RisPort?wsdl'
SRV_location='https://'+SRV_CMSERVER+':'+SRV_axl_port+'/realtimeservice/services/RisPort'

Note that  srv_api_user should be a part of AXLUsers, Standard CCM Admin Users and Standart CCM Super Users groups.

4) Here comes the one and only class cmdevices. It will have cur_layout and prev_layout vars – lists of dictionaries where we will store device name (as it appears in CUCM), directory number, description, IP, registration status, and model. When initializing in stance of the class I’m going to run update_current_states() method to populate cur_layout (we’ll come to this method later), and add Stat_change_at and Stat_change_reason keys to layouts to indicate when registration status has changed and what what the reason for that.

class cmdevices(object):
    cur_layout=[]  
    prev_layout=[]  
    def __init__(self):      
         self.update_current_states()      
         self.prev_layout=self.cur_layout      
         for i in range(len(self.prev_layout)):          
             self.prev_layout[i]['Stat_change_at']=datetime.now()          
             self.prev_layout[i]['Stat_change_reason']= '1strun'

5) Main method of the class would be update_current_states. It’s going to communicate with CUCM, and query it for device states.

def update_current_states(self):
    layout=[]     
    layout_reduce=[]     
    for model in MODELS:         
        t = HttpAuthenticated(username=SRV_user, password=SRV_passwd)         
        t.handler=urllib2.HTTPBasicAuthHandler(t.pm)         
        ssl_def_context = ssl.create_default_context()         
        ssl_def_context.check_hostname = False         
        ssl_def_context.verify_mode = ssl.CERT_NONE         
        t1=urllib2.HTTPSHandler(context=ssl_def_context)         
        t.urlopener = urllib2.build_opener(t.handler,t1)         
        tns = 'http://schemas.cisco.com/ast/soap/'         
        imp=Import('http://schemas.xmlsoap.org/soap/encoding/', 'http://schemas.xmlsoap.org/soap/encoding/')         
        imp.filter.add(tns)
        client=Client(SRV_wsdl,location=SRV_location,plugins=[ImportDoctor(imp)],transport=t)         
        result = client.service.SelectCmDevice('',{'SelectBy':'Name', 'Class':'Phone', 'Model':model})         
        for node in result['SelectCmDeviceResult']['CmNodes']:             
            for device in node['CmDevices'] 
                layout.append({ 'Name':str(device['Name']),                                 
                                 'DN':str(device['DirNumber'])[:4],
                                 'Description':str(device['Description']),
                                 'IP': str(device['IpAddress']),
                                 'Status':str(device['Status']),
                                 'Model':str(MODELS[device['Model']])})     
       
    return True

First part is obvious – we are connecting to CUCM using default ssl context with Basic Auth and mend our schema with Doctor from suds. But I noticed that of one of the devices lost registration with it’s first CUCM from CM_Group and register with the second Serviceability API will list this device as unregistered with 1st node and registered with the second. Let’s call this status split and assume that in that case device is registered. So you have to parse returne layout to sort this out.

6) Last method of the class you have to implement will fetch for current states from CUCM and analyze changes comparing cur_layout and prev_layout

7) That’s it – in the main part of the script you should create an instance of the class and call update_changes periodically (I personally use apscheduler python module for that) display information you are interested in from cur_layout of the instance. You can go beyond with it as I did and use Flask framework to launch web-server and show device registration status on a web page with automatic refresh.