Collecting alarms from CUCM

In RTMT there is a separate menu named “Alert Central”, where all active and history alarms of CUCM and IM&P nodes are listed. RTMT communicates with Cisco AMC service to get this info anomg other real-time data.

Service parameters for Cisco AMC looks like that:

333

Primary collector is a node (CUCM or IM&P) which would collect logs from other nodes. Cisco suggest to choose least busy node for it. After changing Primary collector AMC service should be restarted on every node.

Logger enabled switch allows AMC logs to be saved as csv files that can be queried later.

Alert files can be found on Primary collector by issuing CLI command

file list activelog cm/log/amc/AlertLog

Files in this directory are generated at midnight every day or when AMC is restarted and file format is AlertLog_MM_DD_YYYY_HH_MM.csv (last part of HH_MM is usually 00_00 or 00_01).

In order to obtain these files programatically there is a special API for that. Here is a simple python script to get the file with alarms:


import requests
def getOneFile(node,user,passw,filename):
    header={'SOAPAction':'http://schemas.cisco.com/ast/soap/action/#LogCollectionPort#GetOneFile'}
    raw_xml = """<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://schemas.cisco.com/ast/soap/">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:GetOneFile soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <FileName xsi:type="get:FileName" xmlns:get="http://cisco.com/ccm/serviceability/soap/LogCollection/GetFile/">/var/log/active/tomcat/logs/manager.2016-02-11.log</FileName>
      </soap:GetOneFile>
   </soapenv:Body>
</soapenv:Envelope>""".format(filename)
    try:
        response=requests.post('https://'+node+':8443/logcollectionservice/services/DimeGetFileService',data=raw_xml,auth=requests.auth.HTTPBasicAuth(user,passw),verify=False,headers = header)
        return response.text
    except:
        return -1
if __name__ == '__main__':
    print getOneFile('192.168.0.1','admin','admin','/var/log/active/cm/log/amc/AlertLog/AlertLog_02_08_2016_00_00.csv')


The user, which queries the file might be your administrator Application user with access to AXL applications.

The output should look like this:

Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <80DB2208357F8BD76EE58C1967C79E0D>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <ns1:GetOneFileResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.cisco.com/ast/soap/">
            <DataHandler href="cid:BC0EDD33C6D0C7A1F6286E3691F95332" xsi:type="ns2:DataHandler" xmlns:ns2="DimeGetFileService"/>
        </ns1:GetOneFileResponse>
    </soapenv:Body>
</soapenv:Envelope>

Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-Id: <BC0EDD33C6D0C7A1F6286E3691F95332>

Time Stamp,Alert Type,Alert Name,Alert Message,Monitored Object Name,Severity,PollValue,Action,Node ID,Group ID
1454882401636,0,CriticalServiceDown, Service operational status is DOWN. Cisco Presence Engine. The alert is generated on Mon Feb 08 00:00:01 EET 2016 on node 192.168.0.34., ,2,0,admin@exmaple.com;,192.168.0.34,System
1454882431615,0,CriticalServiceDown, Service operational status is DOWN. Cisco Presence Engine. The alert is generated on Mon Feb 08 00:00:31 EET 2016 on node 192.168.0.34., ,2,0,admin@exmaple.com;,192.168.0.34,System

 

As you can see the last part of the output is the content of the file with alarms thrown by CUCM and IM&P, where every line start with a timestamp (with milliseconds). So parsing this output is rather simple.

With this in mind you can create a zabbix server check and monitor UC alarm with common software and stop relying to emails and RTMT.

Cisco Jabber update 11.5

There is a known vulnerability in Cisco Jabber versions lower than 11.5 http://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20151224-jab. So I decided to perform a cetralized update on my user’s PCs and MACs.
First thing to to is to implement automatic upgrades
1) Go to Cisco Unified Operating System Administration -> Software upgrades -> TFTP File Management and look for jabber-config.xml. It can be also accessed from http://<cucm IP>:6970/jabber-config.xml.
2) Download it to your PC and edit it to add Client section like this

<config version="1.0">
<Client>
<UpdateURL>http://<your 3rd party web server>/jabber-update.xml</UpdateURL>
</Client>

3) Upload it to CUCM TFTP: Cisco Unified Operating System Administration -> Software upgrades -> TFTP File Management -> Upload file to / directory. Then restart TFTP service on every CUCM node (I’m not completely sure if it’s needed at all as updated file appears even without restart)

4) Now host a file named jabber-update.xml  on a 3rd party web server. It should look like that:

<JabberUpdate>
  <App name="JabberMac">
     <LatestBuildNum>226858</LatestBuildNum>
     <LatestVersion>11.5.0</LatestVersion>
     <Message>This new version of Cisco Jabber</Message>
     <DownloadURL>http://<your 3rd party web server>/Cisco-Jabber-Mac-11.5.0.226858-<long string with random characters - see below for info>.zip</DownloadURL>
  </App>
  <App name="JabberWin">
     <LatestBuildNum>26858</LatestBuildNum>
     <LatestVersion>11.5.0</LatestVersion>
     <Message>This new version of Cisco Jabber</Message>
     <DownloadURL>http://<your 3rd party web server>/CiscoJabberSetup-11.5.0.26858.msi</DownloadURL>
  </App>
</JabberUpdate>

This long string with random characters in the file for update of MAC version can be found in release notes. But I consulted Cisco TAC because there were no release notes in download portal at Cisco.com when I was there that moment. And of course these zip and msi install files should be also accessible and biuld and version number should be consistent.

5) Now every user who will restart Cisco Jabber would get a message which encourages them to upgrade. But they can skip it unless you specify <Mandatory>true</Mandatory> in jabber-update.xml.
6) In order to check upgrade status I use RTMT. Go to Voice/Video -> Device -> Device Search -> Phone. Choose Any status, Any protocol, Any model, and Device name like CSF* and it will show a table with all CSF devices and their active load
7) If you want to export it you should use CLI:
– login to CLI with platform admin
– issue show risdb query phones file alldevices to create file alldevices.txt inside  platform/cli/ folder which lists all devices and their active loads.
– issue file get activelog platform/cli/alldevices.txt to upload it to SFTP server. CLI would ask a couple of questions about IP of SFTP, username/password, direcotry and correctness of server fingerprint. I’m using freeFTPd (http://www.freesshd.com/?ctt=download) as SFTP which very easy to install.
– repeat it for every CUCM node (every one with CallManager service running) as show risdb query phones will list devices registered only for the node it’s run on.

Now you have a file with list of every device in CUCM. I use Excel to sort it and extract only CFS devices. In most cases you can find user login right after CFS in device name so it should be easy to spot lazy users.
This approach has some restrictions as it will list only Cisco Jabber users that are using phone services and leave those who use only IM. Moreover RTMT and show risdb will list devices with statuses of Registered/Unregistered and not the ones with None status which
indocates that these users launched their Cisco Jabber quite some time ago.

Hunt pilot alerting name

Hunt pilot is a cool CUCM feature  that allows you to spread an incoming call across multiple lines. In version 10 of CUCM Cisco added queueing capabilities introducing tiny call-center.
Hunt pilot setup follows standard CUCM 3-tier configuration scheme: hunt pilot number refers to a hunt list which is a sorted list of line groups. The latter are the groups of DNs.
This allows you to have a DN in multiple line groups. But here is a complication: when someone calls a Hunt pilot the recipient sees a calling number of this someone and not the hunt pilot.
What if it’s a sales manager that is a member of hunt pilots and he have difference greetings for each hunt pilot number?
There is a Advanced clusterwide service parameter for CallManager service, which allows our sales manager to identify a hunt pilot he’s been reached from:

1

In hunt pilot configuration page you can set alerting names:

2

Calling Line ID Presentation and Calling Name Presentation should be set to Allow if you want a called party to see who’s calling (not the hunt pilot alerting name but caller id). Connected Line ID Presentation and Connected Line ID Presentation  should be set to Allow if you want a called party to see resulting DN Caller ID once on call.

The result should look like that for Cisco Jabber notification:

3

and on a phone screen:

4

The default behaviour for this function is enabled for CUCM of version >10. But I’m not sure when this parameter was introduced and I think that this feature would be switched off after upgrade from a version where it was absent.

 

 

3rd party SIP device and CUCM

Adding 3rd party SIP device to CUCM is pretty straightforward: add End User with digest credentials, create SIP profile with Digest authentication support, add 3rd party SIP device (choose advanced for video) and apply config on the device itself (you should usually specify DN, end user name and digest credentials). Here is the link to cisco.com which describes the process.

But recently I encountered that my Lifesize video codec refused to register on CUCM. TCPdump showed that device sent SIP register, CUCM replied with 401 Unauthorized with all necessary info for authentication (Digest realm=”ccmsipline”, nonce=”some long random line”, algorithm=MD5), which was OK. When Lifesize calculated the response and sent it with subsequent SIP REGISTER, CUCM replied with 500 Internal Server Error:

5001

Before submitting a TAC case I decided to check device config on CUCM. There is a configuration parameter of Device Pool assigned to device. This pool define CMgroup among other things. Cisco phones download their configuration files  where they can find CUCM nodes they can register to, which is not the case with 3rd party SIP devices.

Now back to Lifesize configuration window: in SIP Registration hostname field I specified a node which was not in the CMgroup assigned to the device. When I changed it to appropriate hostname, Lifesize registered normally.

URI dialling in UC infrastructure. Part 2.

As soon as your endpoints – codecs and Cisco Jabber client – are registered to CUCM and ready to dial each other URIs it’s time to try dialling to an external URI,
that is outside our enterprise. External URIs could be one of the following types:
1) a normal SIP URI in a form of info@example.com where example.com domain has appropriate SRV records (_sip._udp SRV 0 5060 host.example.com. for example for SIP over UDP)
2) a SIP URI in a form of info@1.2.3.4 with an IP address in place of the domain
3) an IP address – usually guys with Polycom systems use it along with H323 protocol.
4) exotic URIs like 1.2.3.4##12345 used also by some Polycom systems – they usually can be accesses by a standard URI of 12345@1.2.3.4 or by IP 1.2.3.4

If you have only CUCM in your network you can dial only type 1 and 2. For that case you can create a SIP Route Pattern with domain routing for type1 and with IP routing with type2. I can’t definitely say why CUCM has there two flavours of SIP route patterns – my guess is that IP address notation of 192.168.0.1 can bee seen by CUCM as a domain with 4 levels and it tries an SRV lookup (for _sip._udp.192.168.0.1) instead just using this IP address for network layer.

In order to cover all possible destinations – all types of URIs and both signalling protocols – it’s better to have an Collaboration Edge servers installed. They come in two versions: VCS-E/C which supports registrations of endpoints and
Expressway-E/C which relays endpoint registrations to CUCM in case of MRA.

So, first you need a SIP route pattern *.* with domain routing in CUCM pointing to a SIP trunk (a Route list in my case as I have a clustered pair of Expressway and two SIP trunks).

1

According to this document http://www.cisco.com/c/dam/en/us/td/docs/voice_ip_comm/expressway/config_guide/X8-2/Mobile-Remote-Access-via-Expressway-Deployment-Guide-X8-2.pdf on page 30 you have to have a new  SIP Trunk Security Profile with non-standard SIP listening port for Expressway-CUCM integration to work.

This route pattern easily covers type 1 URIs. In order to dial type 2 URIs you should add a separate SIP route pattern with IP routing and specify exact IP address (and I don’t know the way to make it more flexible now).
To cover type 3 URI we will convert IP addresses to URIs with some user training and special search rules on Collaboration Edge servers.

On Expressway-C I’ve created a separate from automatically created MRA zones neighbour zone toward CUCM.

2

And configured a search rule for URI dialing. When a requests is received from CUCM Expressway-C just sends it to Traversal zone (and my traversal zone is SIP only). That shoud cover type 1 URIs

3

For dialing by IP (type 3) IP I’ve found a post http://www.ucguerrilla.com/2014/02/cisco-telepresence-endpoints-and-ip.html which suggested a using special type of URI for that.
You should instruct your users to dial 192.168.0.100@ip.local to reach external endpoint 192.168.0.100 – this effectively converts pure IP dialling to standard URI dialling.
When the request with 192.168.0.100@ip.local reaches Expressway-C the transform would convert it to IP address

4

Then for type 2 and type 3 (converted to IP address by transform)  URIs there is a separate Search rule:

6

Moreover under  Configuration -> Dial plan -> Configuration Calls to unknown IP addresses should be set to Indirect on Expressway-C for it to work.

On Internet facing Expressway-E acting as traversal server I set up a DNS zone and a search rule with pretty standard configuration.

7

9

It will deal with type 1 URIs making DNS SRV and even DNS A/AAAA lookups for H323 and SIP.

But in order to support both SIP and H32 you should have H323-SIP Interworking Gateway option key installed, and SIP-H323 interworking  turned on under Configuration -> Protocols -> interworking. And you don’t need a DNS zone for IP dialling (both type 2 and type 3) as it will be covered by option Configuration -> Dial plan -> Configuration Calls to unknown IP addresses set to direct.

URI dialling in UC infrastructure. Part 1.

URI dialling in UC infrastructure is a good thing to have for a number of reasons. For example, if your dial plan is not flexible enough and the number of digits used for DNs is insufficient to cover all endpoints. In that case moving toward URI will give you more flexibility (in case you don’t want to enable access codes).
Another reason that sounds tempting is the expansion of Cisco Jabber usage: some of my users don’t want a hardware phone any more and ask to give them the opportunity to make and receive call with Jabber only. In that case I can leave them with Directory URI only which is equal to their email, which is nice.
Moreover, URI dialling is essential when making B2B calls.
So here I’m going to cover some potential cases of URI dialling with CUCM and VCS/Expressway

1) Cisco video codecs

SX10 and SX20 codecs are very powerful devices. If they are not provisioned by CUCM or VCS they can dial via URI out-of-the-box provided SIP and H.323 protocols are on and there is no SIP proxy of H.323 gatekeeper configured.

For example, if you dial reception@example.com from a SX20 it will do the necessary DNS lookups for example.com domain and send SIP INVITE to the corresponding IP.

But in most cases codecs are managed by CUCM and all SIP INVITES are send to it. In that case you need to set up intracluster/intercluster URI dialling on CUCM and B2B dialling through collaboration edge VCS/Expressway.
I still keep H.323 protocol enabled (Configuration->System configuration->Networkservices->H323 ON) for SX20 to be capable of calling H323 destinations on its own.

2) Cisco Jabber

Jabber calling capabilities are managed and provisioned by CUCM by using special type of devices (i.e, CSF for Cisco Jabber for windows).  If you want to make calls to URI from Jabber you should enable this function in jabber-config.xml

  • download jabber-config.xml from CUCM TFTP by navigating to http://%5BIP address of CUCM node with TFTP running]:6970/jabber-config.xml
  • in the policies section change EnableSIPURIDialling parameter to true
  • upload updated jabber-config.xml to TFTP via Cisco Unified Operating System Administration -> Software updates -> TFTP File Management  -> Upload file (use / directory)
  • restart TFTP service

After restarting Cisco Jabber your devices will be able to use URIs.

3) Intracluster URI dialling
There is a document on cisco.com describing the process of enabling intracluster URIs. I want to expand it a little bit.
If you have you user account synchronized with LDAP, their URI could be imported to CUCM as a part of this synchronization. Navigate to Cisco Unified CM Administration ->End User -> select a user.
In End User Configuration window there should be a populated Directory URI filed. Then scroll down and find Directory Number Associations.

1
The drop-down Primary Extension will be populated if an end user has a control of a device with DN configured (see Device Information -> Controlled Devices in this window). So when you choose a DN user’s Direcotry URI get’s assosiated with this DN and is automatically assigned to a partition defined by  System -> Enterprise Parameters -> End User Parameters -> Directory URI Alias Partition. Be sure to add this partition to a correspondent CSS.

Another option is to define custom (up to 5 different) URIs under DN configuration.  Navigate to a device -> Association (DN association section on the left), scroll down to Directory URIs section and add one (and choose a partition). If you have already completed first option via  End User Configuration window, in that case Directory URI will show up here with a green OK sign.

2
And don’t forget to check Use Fully Qualified Domain Name in SIP Requests checkbox in all SIP profiles used by Cisco Jabber devices and codecs.

Now you can use URI for calling between Jabber and video codecs inside you CUCM cluster

4) Intercluster URI dialling
This task is accomplished with ILS,which I think deserves a separate post.

In part 2 I’m going to cover B2B URI dialling both inbound and outbound.

Video broadcasting and recording with Cisco part 1. CUCM+TCS

I’m lucky enough to get my hands on Cisco Telepresence Content Server and in this series I”m going to show how to setup video broadcasting and streaming with Cisco UCM, TCS, Wowza Media Sreaming Engine, nginx and flowplayer. In the end we will able to stream every conference or call from or to Cisco codec controlled by CUCM to user’s browser.

Let’s start with Cisco Unified CM. All we need here is to set up SIP trunk and route pattern which will point to that trunk.

1) Navigate to Cisco Unified CM Administration -> Device -> Trunk -> Add new and create SIP trunk with following parameters

Product:  SIP Trunk
Device Protocol:  SIP
Trunk Service Type: None(Default)
Device Name: cisco_tcs
Device Pool: (depends on your installation)
Call Classification: On-net
Location:  (depends on your installation)
Calling Search Space:  (depends on your installation)
SIP Information Destianation: IP address of TCS
SIP Trunk Security Profile: Non secure SIP trunk profile for Conductor (my CUCM has it preinstalled)
SIP Profile:  SIP trunk for Conductor (you can check http://www.cisco.com/c/dam/en/us/td/docs/telepresence/infrastructure/conductor/config_guide/xc3-0_docs/TelePresence-Conductor-Certificate-Deployment-Guide-XC3-0.pdf for more details on these profiles)

All other parameters marked with * (that is they are mandatory) are good with defaults.

2) Navigate to Cisco Unified CM Administration -> Call Routing -> Route/Hunt -> Route pattern -> Add new and create new pattern that can be called from video codecs

Route Pattern: 100[1-2] (for the sake of simplicity 1001 is going to be used for recording and 1002 for streaming)
Gateway/Route List: cisco_tcs

That’s it to CUCM – now codecs can dial 1001 and 1002 provided Partition and CSS setups are allright.

3) Let’s go to Cisco TCS web page ( <ip address of the server>/tcs) and navigate to Management -> Recording setup -> Templates and add a couple

1st for recording with following settings

2nd for live streaming

Note that there is a field for Media server configuration – we will get to it in part 2.

4) Navigate to Management -> Recording setup -> Recording Alias and add 2 aliases

1st – 1001 for recording (using On demand template)

2nd – 1002 for streaming

That’s it. Now we are able to call 1001 and this call will be recorded. You can download it later using TCS web interface and I will show how to get download URL with TCS API.

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.