In this section, you will implement the following CUCM Serviceability XML API tasks in your Provisioning Portal API:
Earlier you used Python to retrieve information from the Serviceability XML API. You will now incorporate similar functionality into the portal to retrieve the phone device registration details from your CUCM Real-Time Information Database. You will achieve this by leveraging the global CUCM SOAP API Python class mySXMLRisPort70Service that you instantiated earlier.
With the help of your CUCM SOAP API Python class mySXMLRisPort70Service you will send a selectCMDevice RisPort70 API request and relay the response if successful.
The first part of this code is just parsing through the input parameters and then creating the data structure that is required for the selectCMDevice API call. Once the data is in the right format, the ris_query method is called. This API call queries CUCM for the real-time information of the devices that match the search criteria and returns a dictionary with the results. The data is extracted from the result and returned as part of the apiresult.
Next let's work on the code to get CUCM Services Status using the Portal API. You will achieve this by leveraging the global CUCM SOAP API Python class mySXMLControlCenterServicesService that you instantiated earlier.
With the help of your CUCM SOAP API Python class mySXMLControlCenterServicesService you will send a soapGetServiceStatus Control Center Services API request and relay the response if successful.
Like the previous example, this code is just parsing through the input parameters and then creating the data structure that is required for the soapGetServiceStatus API call. Once the data is in the right format, the ccs_get_service_status method is called. This API call queries CUCM for the status of the services that match the search criteria and returns a dictionary with the results. The data is extracted from the result and returned as part of the apiresult.
Next you will implement the ability to retrieve CUCM performance counters in the Portal API. You will achieve this by leveraging the global CUCM SOAP API Python class mySXMLControlCenterServicesService that you instantiated earlier.
This Portal API will execute the following logic:
With the help of the CUCM SOAP API Python class mySXMLPerfMonService and the input parameters supplied you will execute the following CUCM PerfMon API methods in order to efficiently retrieve the performance monitoring counters' values.
and relay a final response if all PerfMon API requests are successful.
Again, this is quite a bit of code but it is just parsing through the input parameters and depending on what is passed, it will construct the list of performance counters in the format that is required for the perfmonAddCounter API call. The counters are then passed to the perfmon_collect_session_data method which queries CUCM for the performance counter values and returns a dictionary with the results. According to the documentation, some counters do not return a result on the first query and require some time for the data to be populated. As a result, if the counter name includes a "%" or "Percentage", the code will pause for 5 seconds and collect the data again. The data is extracted from the result and returned as part of the apiresult after closing the session.
If you were writing an application that needed to poll these counters on a regular basis, you would not close the session after each query. Instead, you would open the session once and then add the counters and collect the data as needed. You would only close the session when you were done polling the counters.
You have added even more capabilities to your Provisioning Portal's APIs, now it is time to make sure it all works as expected, again utilizing your Portal's RESTPlus/Swagger UI page.
{ "TotalDevicesFound": 1, "message": "Device Search Results Retrieved Successfully", "ris_search_result": { "SelectCmDeviceResult": { "CmNodes": { "item": [ { "CmDevices": { "item": [ { "ActiveLoadID": "Webex_for_Windows-45.1.0.31549", ... "Description": "Cisco Live LTRCOL-2574 - pod6ucmuser", "DeviceClass": "Phone", "DirNumber": "\+19197060001-UnRegistered", "DownloadFailureReason": null, "DownloadServer": null, "DownloadStatus": "Unknown", ... "Httpd": "No", "IPAddress": { "item": [ { "Attribute": "Unknown", "IP": "10.0.106.45", "IPAddrType": "ipv4" } ] }, "InactiveLoadID": "Webex_for_Windows-45.1.0.31549", "IsCtiControllable": true, "LinesStatus": { "item": [ { "DirectoryNumber": "\+19197060001", "Status": "UnRegistered" } ] }, "LoginUserId": "pod6ucmuser", "Model": 503, "Name": "CSFPOD6UCMUSER", "NumOfLines": 1, "PerfMonObject": 2, "Product": 390, "Protocol": "SIP", "RegistrationAttempts": 0, "Status": "UnRegistered", "StatusReason": 0, "TimeStamp": 1654799252 } ] }, "Name": "cucm1a.pod6.col.lab", "NoChange": false, "ReturnCode": "Ok" } ] }, "TotalDevicesFound": 1 }, "StateInfo": "" }, "success": true }
If you recall, you deleted this CSF device in the last section, so you might be wondering why you are still getting a result back from this API call. The Real-time Information System (RIS) database is an in-memory store and does not pay attention to what is in the CUCM database. RIS will maintain information about unregistered devices for a period of time, even if the device has been deleted from the database. The in-memory store cleanup is controlled via CUCM RIS Data Collector Service Parameter named RIS Unused Cisco CallManager Device Store Period which defaults to 3 days and could be as high as 30 days.
{ "message": "Service(s) Status Info Retrieved Successfully", "service_info": { "ReasonCode": -1, "ReasonString": null, "ReturnCode": { "_value_1": "0" }, "ServiceInfoList": { "item": [ { "ReasonCode": -1, "ReasonCodeString": " ", "ServiceName": "Cisco CallManager", "ServiceStatus": "Started", "StartTime": "Wed Feb 5 09:15:51 2025", "UpTime": 1108052 }, { "ReasonCode": -1, "ReasonCodeString": " ", "ServiceName": "Cisco Tftp", "ServiceStatus": "Started", "StartTime": "Wed Feb 5 09:16:51 2025", "UpTime": 1108044 } ] } }, "success": true }
{ "message": "PerfMon Data Retrieved Successfully", "perfmon_class_result": [ { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\Allocated FDs" }, "Value": 7712 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\Being Used FDs" }, "Value": 7712 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\Freed FDs" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOAwait" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOCpuUtil" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOKBytesReadPerSecond" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOKBytesWrittenPerSecond" }, "Value": 229 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOPerSecond" }, "Value": 24 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOReadReqMergedPerSecond" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOReadReqPerSecond" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOReqQueueSizeAvg" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOSectorsReadPerSecond" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOSectorsReqSizeAvg" }, "Value": 18 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOSectorsWrittenPerSecond" }, "Value": 458 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOServiceTime" }, "Value": 0 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOWriteReqMergedPerSecond" }, "Value": 8 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\IOWriteReqPerSecond" }, "Value": 24 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\Max FDs" }, "Value": 582286 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\Total CPU Time" }, "Value": 109266374 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\Total Processes" }, "Value": 207 }, { "CStatus": 1, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\System\\Total Threads" }, "Value": 1138 } ], "perfmon_counters_result": [ { "CStatus": 0, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\Cisco CallManager\\RegisteredOtherStationDevices" }, "Value": 2 }, { "CStatus": 0, "Name": { "_value_1": "\\\\cucm1a.pod6.col.lab\\Cisco Tomcat Connector(http-bio-8443)\\ThreadsBusy" }, "Value": 1 } ], "success": true }
Notice that the query included the System class and two counters. The response includes the values of the all the counters in the System class and the two counters that were queried.
You have now added some core CUCM monitoring capabilities to your Portal APIs that allows you to keep an eye on the health and operational state of your CUCM servers. Let's add some core REST API capabilities to your Portal which will help you with Webex APIs.