예제 #1
0
def main():
    """
    This sample script will show how to work with the device configurations using NETCONF and RESTCONF
    """

    # retrieve the device capabilities using RESTCONF
    print('Device Capabilities via RESTCONF: ')
    capabilities = netconf_restconf.restconf_get_capabilities(
        IOS_XE_HOST, IOS_XE_USER, IOS_XE_PASS)
    print(json.dumps(capabilities, indent=4, separators=(' , ', ' : ')))

    # retrieve the device hostname using RESTCONF
    device_hostname = netconf_restconf.restconf_get_hostname(
        IOS_XE_HOST, IOS_XE_USER, IOS_XE_PASS)
    print(str('\nDevice Hostname via RESTCONF: \n' + device_hostname))

    # retrieve interface operationla state using NETCONF
    interface_state = netconf_restconf.netconf_get_int_oper_status(
        'GigabitEthernet1', IOS_XE_HOST, IOS_XE_PORT, IOS_XE_USER, IOS_XE_PASS)
    print(
        str('\nInterface Operational Status via NETCONF: \n' +
            interface_state))

    # retrieve the interface statistics using RESTCONF
    interface_statistics = netconf_restconf.restconf_get_int_oper_data(
        'GigabitEthernet1', IOS_XE_HOST, IOS_XE_USER, IOS_XE_PASS)
    print('\nGigabitEthernet1 Interface Statistics via RESTCONF: \n')
    print(json.dumps(interface_statistics, indent=4,
                     separators=(' , ', ' : ')))

    # save running configuration to startup configuration using RESTCONF
    save_result = netconf_restconf.restconf_save_running_config(
        IOS_XE_HOST, IOS_XE_USER, IOS_XE_PASS)
    print('\nRunning Config saved to device using RESTCONF: ', save_result)

    # save running configuration to file using NETCONF
    save_file = 'flash:/CONFIG_FILES/base_config'
    save_file_result = netconf_restconf.netconf_save_running_config_to_file(
        save_file, IOS_XE_HOST, IOS_XE_PORT, IOS_XE_USER, IOS_XE_PASS)
    print('\nRunning Config saved to file using NETCONF: ',
          save_file_result[1])

    # rollback configuration to saved file using RESTCONF
    rollback_file = 'flash:/CONFIG_FILES/base_config'
    rollback_result = netconf_restconf.restconf_rollback_to_saved_config(
        rollback_file, IOS_XE_HOST, IOS_XE_USER, IOS_XE_PASS)
    print('\nRollback of Config from saved file using RESTCONF: ',
          rollback_result)
예제 #2
0
def main():
    """
    This script will monitor device configuration changes. It could be executed on demand,
    periodically (every 60 minutes, for example) or continuously.
    It will collect the configuration file for each DNA Center managed device, compare with the existing cached file,
    and detect if any changes.
    When changes detected, identify the last user that configured the device, and create a new ServiceNow incident.
    Automatically roll back all non-compliant configurations, or save new configurations if approved in ServiceNow.
    Device configuration files managemnt using RESTCONF and NETCONF
    Compliance checks at this time:
    - no Access Control Lists changes
    - no logging changes
    - no duplicated IPv4 addresses
    """

    # run the demo continuously, looping

    print('Application config_mon.py started')
    # create a local directory for all the configuration files
    # check if 'Config_Files' folder exists and create one if it does not

    if not os.path.exists('Config_Files'):
        os.makedirs('Config_Files')

    os.chdir('Config_Files')

    # logging, debug level, to file {application_run.log}
    logging.basicConfig(
        filename='application_run.log',
        level=logging.DEBUG,
        format=
        '%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S')

    while True:

        # get the DNA C auth token
        dnac_token = dnac_apis.get_dnac_jwt_token(DNAC_AUTH)
        print('\nDNA C AUTH TOKEN: ', dnac_token, '\n')

        temp_run_config = 'temp_run_config.txt'

        # get the DNA C managed devices list (excluded wireless, for one location)
        all_devices_info = dnac_apis.get_all_device_info(dnac_token)
        all_devices_hostnames = []
        for device in all_devices_info:
            if device['family'] == 'Switches and Hubs' or device[
                    'family'] == 'Routers':
                if IOS_XE_HOSTNAME in device['hostname']:
                    all_devices_hostnames.append(device['hostname'])

        # get the config files, compare with existing (if one existing). Save new config if file not existing.
        for device in all_devices_hostnames:
            device_run_config = dnac_apis.get_output_command_runner(
                'show running-config', device, dnac_token)
            filename = str(device) + '_run_config.txt'

            # save the running config to a temp file

            f_temp = open(temp_run_config, 'w')
            f_temp.write(device_run_config)
            f_temp.seek(0)  # reset the file pointer to 0
            f_temp.close()

            # check if device has an existing configuration file (to account for newly discovered DNA C devices)
            # if yes, run the diff function
            # if not, save the device configuration to the local device database
            # this will create the local "database" of configs, one file/device

            if os.path.isfile(filename):
                diff = compare_configs(filename, temp_run_config)

                if diff != '':

                    # retrieve the device location using DNA C REST APIs
                    location = dnac_apis.get_device_location(
                        device, dnac_token)

                    # find the users that made configuration changes
                    with open(temp_run_config, 'r') as f:
                        user_info = 'User info no available'
                        for line in f:
                            if 'Last configuration change' in line:
                                user_info = line

                    # define the incident description and comment
                    short_description = 'Configuration Change Alert - ' + device
                    comment = 'The device with the name: ' + device + '\nhas detected a Configuration Change'

                    print(comment)

                    # create ServiceNow incident using ServiceNow APIs
                    incident = service_now_apis.create_incident(
                        short_description, comment, SNOW_DEV, 3)

                    # get the device health from DNA Center
                    current_time_epoch = utils.get_epoch_current_time()
                    device_details = dnac_apis.get_device_health(
                        device, current_time_epoch, dnac_token)

                    device_sn = device_details['serialNumber']
                    private_mngmnt_ip_address = device_details[
                        'managementIpAddr']
                    device_mngmnt_ip_address = NAT[private_mngmnt_ip_address]
                    device_family = device_details['platformId']
                    device_os_info = device_details[
                        'osType'] + ',  ' + device_details['softwareVersion']
                    device_health = device_details['overallHealth']

                    updated_comment = '\nDevice location: ' + location
                    updated_comment += '\nDevice family: ' + device_family
                    updated_comment += '\nDevice OS info: ' + device_os_info
                    updated_comment += '\nDevice S/N: ' + device_sn
                    updated_comment += '\nDevice Health: ' + str(
                        device_health) + '/10'
                    updated_comment += '\nDevice management IP address: ' + device_mngmnt_ip_address

                    print(updated_comment)

                    # update ServiceNow incident
                    service_now_apis.update_incident(incident, updated_comment,
                                                     SNOW_DEV)

                    updated_comment = '\nThe configuration changes are\n' + diff + '\n\n' + user_info

                    print(updated_comment)

                    # update ServiceNow incident
                    service_now_apis.update_incident(incident, updated_comment,
                                                     SNOW_DEV)

                    # start the compliance validation
                    # ACL changes
                    validation_result = 'Pass'
                    validation_comment = ''
                    if ('+access-list' in diff) or ('-access-list' in diff):
                        updated_comment = '\nValidation against ACL changes failed'
                        service_now_apis.update_incident(
                            incident, updated_comment, SNOW_DEV)
                        validation_result = 'Failed'
                    else:
                        validation_comment = '\nPassed ACL Policy'

                    # logging changes
                    if ('+logging' in diff) or ('-logging' in diff):
                        updated_comment = '\nValidation against logging changes failed'
                        service_now_apis.update_incident(
                            incident, updated_comment, SNOW_DEV)
                        validation_result = 'Failed'
                    else:
                        validation_comment += '\nPassed Logging Policy'

                    # IPv4 duplicates
                    diff_list = diff.split('\n')
                    diff_config = '!\n'
                    for command in diff_list:
                        if 'ip address' in command:
                            diff_config += command.replace('+', '') + '\n!'

                    # save the diff config that include only IP addresses in a file
                    f_diff = open('temp_config_file.txt', 'w')
                    f_diff.write(diff_config)
                    f_diff.seek(0)  # reset the file pointer to 0
                    f_diff.close()

                    duplicate_ip_result = dnac_apis.check_ipv4_duplicate(
                        'temp_config_file.txt')
                    if duplicate_ip_result:
                        updated_comment = '\nValidation against duplicated IPv4 addresses failed'
                        service_now_apis.update_incident(
                            incident, updated_comment, SNOW_DEV)
                        validation_result = 'Failed'
                    else:
                        validation_comment += '\nPassed Duplicate IPv4 Prevention'

                    print(updated_comment)

                    # procedure to restore configurations as policy validations failed
                    if validation_result == 'Failed':
                        updated_comment = '\nConfiguration changes do not pass validation,\nConfiguration roll back initiated'
                        service_now_apis.update_incident(
                            incident, updated_comment, SNOW_DEV)

                        print(updated_comment)

                        # start the config roll back
                        baseline_config = 'flash:/config_mon_baseline'
                        netconf_restconf.restconf_rollback_to_saved_config(
                            baseline_config, device_mngmnt_ip_address,
                            IOS_XE_USER, IOS_XE_PASS)

                        # check if rollback is successful after 5 seconds
                        time.sleep(5)
                        device_run_config = dnac_apis.get_output_command_runner(
                            'show running-config', device, dnac_token)
                        filename = str(device) + '_run_config.txt'

                        # save the running config to a temp file
                        f_temp = open(temp_run_config, 'w')
                        f_temp.write(device_run_config)
                        f_temp.seek(0)  # reset the file pointer to 0
                        f_temp.close()

                        diff = compare_configs(filename, temp_run_config)
                        if diff != ' ':
                            updated_comment = '\nConfiguration rolled back successfully'
                            service_now_apis.update_incident(
                                incident, updated_comment, SNOW_DEV)
                            # close ServiceNow incident
                            service_now_apis.close_incident(incident, SNOW_DEV)
                        else:
                            updated_comment = '\nConfiguration rolled back not successful'
                            service_now_apis.update_incident(
                                incident, updated_comment, SNOW_DEV)

                    # start procedure to ask for approval as validation passed
                    else:
                        service_now_apis.update_incident(
                            incident, 'Approve these changes (YES/NO)?\n' +
                            validation_comment, SNOW_DEV)
                        service_now_apis.update_incident(
                            incident, 'Waiting for Management Approval',
                            SNOW_DEV)

                        print(
                            '\nConfiguration changes pass compliance checks, approval waiting'
                        )

                        # start the approval YES/NO procedure
                        # start a loop to check for 2 min if approved of not
                        approval = 'NO'
                        timer_count = 0
                        while timer_count <= 5:
                            if service_now_apis.find_comment(incident, 'YES'):

                                # start the save of running config to new baseline on device
                                # flash:/config_mon_baseline

                                netconf_restconf.netconf_save_running_config_to_file(
                                    'flash:/config_mon_baseline',
                                    device_mngmnt_ip_address, IOS_XE_PORT,
                                    IOS_XE_USER, IOS_XE_PASS)

                                print(
                                    'New baseline configuration saved on network device: '
                                    + device)

                                # establish new baseline config on server
                                time.sleep(5)
                                device_run_config = dnac_apis.get_output_command_runner(
                                    'show running-config', device, dnac_token)
                                filename = str(device) + '_run_config.txt'

                                # save the running config to the device config file
                                f_temp = open(filename, 'w')
                                f_temp.write(device_run_config)
                                f_temp.seek(0)  # reset the file pointer to 0
                                f_temp.close()

                                approval = 'YES'

                                # update ServiceNow incident
                                updated_comment = '\nApproval received, saved device configuration, established new baseline configuration'
                                print(updated_comment)

                                service_now_apis.update_incident(
                                    incident, updated_comment, SNOW_DEV)
                                service_now_apis.close_incident(
                                    incident, SNOW_DEV)
                                break
                            elif service_now_apis.find_comment(incident, 'NO'):
                                break
                            else:
                                timer_count += 1
                                time.sleep(10)
                                if timer_count == 5:
                                    service_now_apis.update_incident(
                                        incident, 'Approval Timeout', SNOW_DEV)

                        # check if Approval is 'NO' at the end of the timer
                        if approval == 'NO':

                            # start the config roll back
                            baseline_config = 'flash:/config_mon_baseline'
                            netconf_restconf.restconf_rollback_to_saved_config(
                                baseline_config, device_mngmnt_ip_address,
                                IOS_XE_USER, IOS_XE_PASS)

                            # check if rollback is successful after 3 seconds
                            time.sleep(5)
                            device_run_config = dnac_apis.get_output_command_runner(
                                'show running-config', device, dnac_token)
                            # save the running config to a temp file
                            f_temp = open(temp_run_config, 'w')
                            f_temp.write(device_run_config)
                            f_temp.seek(0)  # reset the file pointer to 0
                            f_temp.close()

                            filename = str(device) + '_run_config.txt'

                            diff = compare_configs(filename, temp_run_config)
                            if diff != ' ':
                                updated_comment = '\nConfiguration changes not approved,\nConfiguration rolled back successfully'
                                print(updated_comment)

                                service_now_apis.update_incident(
                                    incident, updated_comment, SNOW_DEV)
                                service_now_apis.close_incident(
                                    incident, SNOW_DEV)
                            else:
                                updated_comment = '\nConfiguration changes not approved,\nConfiguration rolled back not successful'
                                service_now_apis.update_incident(
                                    incident, updated_comment, SNOW_DEV)

                else:
                    print('Device: ' + device +
                          ' - No configuration changes detected')

            else:
                # new device discovered, save the running configuration to a file in the folder with the name
                # {Config_Files}

                f_config = open(filename, 'w')
                f_config.write(device_run_config)
                f_config.seek(0)
                f_config.close()

                # retrieve the device management IP address

                private_mngmnt_ip_address = dnac_apis.get_device_management_ip(
                    device, dnac_token)
                device_mngmnt_ip_address = NAT[private_mngmnt_ip_address]

                # Save the running configuration as a baseline configuration local on each device
                # flash:/config_mon_baseline

                netconf_restconf.netconf_save_running_config_to_file(
                    'flash:/config_mon_baseline', device_mngmnt_ip_address,
                    IOS_XE_PORT, IOS_XE_USER, IOS_XE_PASS)

                print('Device: ' + device + ' - New device discovered')

        print('Wait for 10 seconds and start again')
        time.sleep(10)

    print('\n\nEnd of Application Run')