Article 5 - Restoring Saved Device Ownership Data

This article covers restoring device ownership information using data stored in a CSV generated by the Python script in the previous article.

To do this we will use a Python script to submit SQL update queries to the CUCM API using device and owner information read from the CSV file.

SQL Query Used to Restore Device Ownership Data

The SQL query we will use to restore the device owner data is shown below.

run sql update device set fkenduser = 'value_of_fkenduser_read_from_csv_file' where pkid = 'value_of_pkid_read_from_csv_file'

This query will be run for each row in the CSV file (excluding the header row) using the pkid and fkenduser values from that row.

The Python Script

The Python script shown below will retrieve the data listed above and save it to a CSV file. The name of the CSV file includes date and time information so that new output files can be created without overwriting existing files.

The script comprises the following high level steps:

  1. Load information needed to connect to the target CUCM server from an ini file.
  2. Ask the user to enter the name of the CSV file that contains the device ownership data to be restored.
  3. Connect to the CUCM AXL API using the settings from the ini file to retrieve and store cookies data.
  4. Open the input CSV file and loop through data.
  5. For each line try to update the device owner using an AXL SQL Update query the fkenduser and devicepkid values for that line.
  6. The result of each SQL Update query is written to a CSV log file along with the device and owner details.
import sys
import requests
from urllib3 import disable_warnings
from urllib3.exceptions import InsecureRequestWarning
from configparser import ConfigParser
import datetime
import pprint
import csv
from csv import DictReader

disable_warnings(InsecureRequestWarning)


########################################################################################################################

def axlgetcookies(serveraddress, version, axluser, axlpassword):
    try:
        # Make AXL query using Requests module
        axlgetcookiessoapresponse = requests.get(f'https://{ipaddr}:8443/axl/', headers=soapheaders, verify=False,\
                                                 auth=(axluser, axlpassword), timeout=3)
        print(axlgetcookiessoapresponse)
        getaxlcookiesresult = axlgetcookiessoapresponse.cookies

        if '200' in str(axlgetcookiessoapresponse):
            # request is successful
            print('AXL Request Successful')
        elif '401' in str(axlgetcookiessoapresponse):
            # request fails due to invalid credentials
            print('Response is 401 Unauthorised - please check credentials')
        else:
            # request fails due to other cause
            print('Request failed! - HTTP Response Code is ' + axlgetcookiessoapresponse)

    except requests.exceptions.Timeout:
        axlgetcookiesresult = 'Error: IP address not found!'

    except requests.exceptions.ConnectionError:
        axlgetcookiesresult = 'Error: DNS lookup failed!'

    return getaxlcookiesresult

########################################################################################################################

def axlupdatedeviceownerdata(cookies,devicepkid,fkenduser):
    # Set SOAP request body
    axlupdatedeviceownerdatasoaprequest = f'<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/{version}"><soapenv:Header/><soapenv:Body><ns:executeSQLUpdate><sql>UPDATE device SET fkenduser = "{fkenduser}" WHERE pkid = "{devicepkid}"</sql></ns:executeSQLUpdate></soapenv:Body></soapenv:Envelope>'

    try:

        # Make SOAP request
        axlupdatedeviceownerdatasoapresponse = requests.post(f'https://{ipaddr}:8443/axl/', data=axlupdatedeviceownerdatasoaprequest, headers=soapheaders, verify=False, cookies=cookies, timeout=9)

        if '200' in str(axlupdatedeviceownerdatasoapresponse):
            # request is successful
            device_update = 'Success'
        else:
            # request is unsuccessful
            device_update = 'Failure'

        return device_update

    except requests.exceptions.Timeout:
        print('IP address not found! ')
    except requests.exceptions.ConnectionError:
        print('DNS lookup failed!  ')


########################################################################################################################

def main():
    # Import values for the CUCM environment from ini file using ConfigParser

    global ipaddr, version, axluser, axlpassword, soapheaders, cookies
    parser = ConfigParser()
    parser.read('cucm-settings.ini')

    ipaddr = parser.get('CUCM', 'ipaddr')
    version = parser.get('CUCM', 'version')
    axluser = parser.get('CUCM', 'axluser')
    axlpassword = parser.get('CUCM', 'axlpassword')
    soapheaders = {'Content-type': 'text/xml', 'SOAPAction': 'CUCM:DB ver=' + version}


    # Ask user for the name of the CSV file that contains the ownership data
    print('*' * 120)
    print()
    print('Python 3.x Script to Restore CUCM User Ownership Data from CSV File')
    print()
    print('Written by James Hawkins, Axonex, July 2017')
    print()
    deviceownerdatainputfile = input('Enter the name of the file containing the device ownership data you wish to restore: ')
    print(deviceownerdatainputfile)

    # Get cookies for future AXL requests
    axlgetcookiesresult = axlgetcookies(ipaddr, version, axluser, axlpassword)
    print(axlgetcookiesresult)

    if 'JSESSIONIDSSO' in str(axlgetcookiesresult):
        print('Cookies Retrieved')

    else:
        sys.exit('Program has ended due to error!')

    # Create filename for output file in format deviceownerdata-year-month-dom-hour-minute-second.csv
    now = datetime.datetime.now()
    outputfile = 'deviceownerupdatelog-' + now.strftime("%Y-%m-%d-%H-%M-%S") + '.csv'

    # Open output log csv file
    deviceownerdataoutputfile = open(outputfile, 'w', newline='')
    deviceownerdataoutputwriter = csv.writer(deviceownerdataoutputfile)
    deviceownerdataoutputwriter.writerow(['devicepkid', 'devicename', 'fkenduser', 'userid', 'Result'])

    # Open input CSV file and read device pkid and fkenduser values
    with open(deviceownerdatainputfile, mode='r') as csv_file:
        csv_dict_reader = DictReader(csv_file)
        for row in csv_dict_reader:
            devicepkid = row['devicepkid']
            devicename = row['devicename']
            fkenduser = row['fkenduser']
            userid = row['userid']

            # Call update device owner function
            update_status = axlupdatedeviceownerdata(axlgetcookiesresult,devicepkid,fkenduser)
            deviceownerdataoutputwriter.writerow([devicepkid,devicename,fkenduser,userid,update_status])
            if update_status == "Success":
                print(f'Success! - User "{userid}" set as the owner of {devicename}')
            else:
                print(f'Failure! - User "{userid}" not set as the owner of {devicename}')

    deviceownerdataoutputfile.close()

########################################################################################################################

if __name__ == "__main__":
    main()

The Output Data

The csv file output should look similar to that shown below - thanks to Donat Studios for providing a tool to convert CSV data to Markdown.

devicepkid devicename fkenduser userid Result
6eb51642-2723-8ceb-0431-6d1f70437fb8 CSFJHAWKINS 8c758cf4-da8c-bd00-53be-a0902f1707e1 jhawkins Success
5a5fbb7b-6b34-7a81-332f-e8bf39bb669d TCTJHAWKINS 8c758cf4-da8c-bd00-53be-a0902f1707e1 jhawkins Success