Sunday, December 4, 2016

Enable Web Admin Interface on Cisco 8861 IP Phone on a 10.5 Call Manager with Python 2.7

If you happen to have the fortune of needing to deploy Cisco 8861 Wi-Fi phones on an EAP-TLS network with User Installed Certificates on a 10.5 Call Manager then this script will help you out.

Call Manager 10.5 has the capability to enable the Web Admin interface on the 8861, but the Call Manager GUI doesn't support enabling it. Without the Web Admin interface, there is no way to actually install your user installed certificate.

- Dietze


#!/Python27/python

#Environment
#OSX/UCM10.5/Python2.7/

import os
import requests
import json
import smtplib
import urllib
import sys

#####GET INFO FROM CALL MANAGER########
cmserver = 'YOUR_CALL_MANAGER_IP_OR_HOSTNAME'
cmport = '8443'
wsdl = "file:" + "/AXLAPI.wsdl"
location = 'https://' + cmserver + ':' + cmport + '/axl/'

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)

##LOCATIONS FOR REALTIME STATUS
##THIS IS FOR RISPORT
RTDS_wsdl = 'https://' + cmserver + ':8443/realtimeservice/services/RisPort?wsdl'
RTDS_location = 'https://' + cmserver + ':' + cmport + '/realtimeservice/services/RisPort'

#SET USER INFO
#MIGHT BE A GOOD IDEA TO ADD READ THIS FROM A FILE OR SOMETHING
username = user_file.readline().strip()
password = user_file.readline().strip()

try:
 #LOG INTO CALL MANAGER AND CREATE CLIENT OBJECT
    client = Client(wsdl,location=location, username=username, password=password, plugins=[ImportDoctor(imp)])
    
    #SETUP REAL TIME DEVICE STATUS CLIENT (NEEDED TO SEARCH BY IP)
    RTDS_client = Client(RTDS_wsdl,location=RTDS_location, username=username, password=password, plugins=[ImportDoctor(imp)])
 
 #PHONE NAME TO SEARCH FOR
    phone_name = 'SEPXXXXXXXXXXXX'
    
    #SET ADMIN PASSWORD FOR THIS PHONE
    phone_admin_password = 'ciscocisco'
    
    #CREATE RESULT OBJECT AFTER A GET PHONE REQUEST
    result = client.service.getPhone(name=phone_name)
    
    #GET MODEL FROM RESULT OBJECT
    model = str(result['return']['phone']['model'])
    print model
    
    #IF THE MODEL IS AN 8861 THEN UPDATE THE PHONE WITH THE VENDOR CONFIG THAT ISNT IN THE CUCM 10.5 GUI
    if model == "Cisco 8861": 
        client.service.updatePhone(name=phone_name,vendorConfig={
            'disableSpeaker':"false",
            'disableSpeakerAndHeadset':"false",
            'pcPort':"0",
            'voiceVlanAccess':"0",
            'webAccess':"1",
            'spanToPCPort':"1",
            'recordingTone':"0",
            'recordingToneLocalVolume':"100",
            'recordingToneRemoteVolume':"50",
            'powerPriority':"0",
            'minimumRingVolume':"0",
            'ehookEnable':"1",
            'headsetWidebandUIControl':"0",
            'headsetWidebandEnable':"0",
            'garp':"1",
            'allCallsOnPrimary':"0",
            'g722CodecSupport':"0",
            'webAdmin':"1",
            'adminPassword':phone_admin_password,
            })
    else:
        raise ValueError("Not a Cisco 8861")

 #RUN SELECT CM DEVICE TO GET THE IP OF THE PHONE WE JUST UPDATED
    RTDS_result = RTDS_client.service.SelectCmDevice('',{'SelectBy':'Name', 'Status':'Registered', 'Class':'Phone', 'SelectItems':{'SelectItem':{'Item':phone_name}}})
    for i in range(0,len(RTDS_result['SelectCmDeviceResult']['CmNodes'])):
        output = str(RTDS_result['SelectCmDeviceResult']['CmNodes'][i]['CmDevices'])
        if (output != '[]'):
            phone = RTDS_result['SelectCmDeviceResult']['CmNodes'][i]['CmDevices']
            ##print output

    ##PRINT PHONES IP
    phone_ipaddress = phone[0]['IpAddress']
    print "Phone IP Address: " + phone_ipaddress
    
    ##RESTART PHONE
    client.service.restartPhone(name=phone_name)
    print "RESETTING PHONE"
    
    print "SUCCESS"
    print "Login @: https://"+phone_ipaddress+":8443\"
    print "admin | "+phone_admin_password
    

except Exception as e:
    print e
    
print 'Done'
###

Saturday, December 3, 2016

Getting Started with Cisco AXL and Python

Lets talk about getting started with Python and Cisco AXL.

AXL is an API that we can use to interact with Call Manager. I was able to get some basic scripts going to automate some more complicated tasks like setting up RDPs or creating route patterns. I won't provide examples of those on this post, but I will in the future.

Firstly, the important part of these scripts is using the WSDL file for your version of CUCM. There are plenty of resources available to find these so I won't include those instructions here. My examples will be on 10.5 unless otherwise noted.

Below is an example of how to get started with AXL and Python. You will need to fill out your Call Manager IP, WSDL file location, CUCM username, password, and an example IP Phone name.

#!/Python27/python

#Environment
#OSX/UCM10.5/Python2.7/


import cgi
import os
import requests
import json
import smtplib
import urllib
import sys

#####GET INFO FROM CALL MANAGER########
cmserver = 'YOUR_CALL_MANAGER_IP_OR_HOSTNAME'
cmport = '8443'
wsdl = "file:" + "/AXLAPI.wsdl"
location = 'https://' + cmserver + ':' + cmport + '/axl/'

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)

##LOCATIONS FOR REALTIME STATUS
##THIS IS FOR RISPORT
RTDS_wsdl = 'https://' + cmserver + ':8443/realtimeservice/services/RisPort?wsdl'
RTDS_location = 'https://' + cmserver + ':' + cmport + '/realtimeservice/services/RisPort'

#SET USER INFO
#MIGHT BE A GOOD IDEA TO ADD READ THIS FROM A FILE OR SOMETHING
username = 'CUCM_USERNAME'
password = 'PASSWORD'

try:
 #LOG INTO CALL MANAGER AND CREATE CLIENT OBJECT
    client = Client(wsdl,location=location, username=username, password=password, plugins=[ImportDoctor(imp)])
    
    #SETUP REAL TIME DEVICE STATUS CLIENT (NEEDED TO SEARCH BY IP)
    RTDS_client = Client(RTDS_wsdl,location=RTDS_location, username=username, password=password, plugins=[ImportDoctor(imp)])
 
 #PHONE NAME TO SEARCH FOR
    phone_name = 'SEPXXXXXXXXXXXX'
    
    #CREATE RESULT OBJECT AFTER A GET PHONE REQUEST
    result = client.service.getPhone(name=phone_name)
    
    #GET MODEL FROM RESULT OBJECT
    model = str(result['return']['phone']['model'])
    print model

 #RUN SELECT CM DEVICE TO GET THE IP OF THE PHONE WE JUST UPDATED
    RTDS_result = RTDS_client.service.SelectCmDevice('',{'SelectBy':'Name', 'Status':'Registered', 'Class':'Phone', 'SelectItems':{'SelectItem':{'Item':phone_name}}})
    for i in range(0,len(RTDS_result['SelectCmDeviceResult']['CmNodes'])):
        output = str(RTDS_result['SelectCmDeviceResult']['CmNodes'][i]['CmDevices'])
        if (output != '[]'):
            phone = RTDS_result['SelectCmDeviceResult']['CmNodes'][i]['CmDevices']
            ##print output

    ##PRINT PHONES IP
    phone_ipaddress = phone[0]['IpAddress']
    print "Phone IP Address: " + phone_ipaddress
    
    ##RESTART PHONE
    client.service.restartPhone(name=phone_name)
    print "RESETTING PHONE"
    
    print "SUCCESS"
    

except Exception as e:
    print e
    
print 'Done'

Friday, December 2, 2016

And thus it begins

As with anything new, this will be a work in progress. I plan on this to be a place where I can post code snippets and labs to help others where I have struggled.

Dietze