def main(): """ - identify any PnP unclaimed APs - map to local database to identify the floor to be provisioned to - claim the device - verify PnP process workflow - re-sync the WLC controller - verify the AP on-boarded using the Cisco DNA Center Inventory - reachability, IP address, access switch info, WLC info - create, update a ServiceNow incident with the information - close ServiceNow incident if PnP completes successfully """ # run the application on demand, scanning for a new device in the Cisco DNA Center PnP Provisioning tab print('\n\nApplication "dnac_pnp_ap.py" started') # device info and site pnp_device_assign = AP_ASSIGN_SITE site_name = pnp_device_assign['site_name'] floor_name = pnp_device_assign['floor_name'] pnp_device_name = pnp_device_assign['device_hostname'] print('\nThis application will assign the device \n', pnp_device_name, ' to the site: ', pnp_device_assign['site_name'] + ' / ' + floor_name) # 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') dnac_token = dnac_apis.get_dnac_jwt_token(DNAC_AUTH) # check if any devices in 'Unclaimed' and 'Initialized' state, if not wait for 10 seconds and run again pnp_unclaimed_device_count = 0 while pnp_unclaimed_device_count == 0: try: pnp_unclaimed_device_count = dnac_apis.pnp_get_device_count( 'Unclaimed', dnac_token) if pnp_unclaimed_device_count != 0: # get the pnp device info pnp_devices_info = dnac_apis.pnp_get_device_list(dnac_token) device_state = pnp_devices_info[0]['deviceInfo']['state'] device_onb_state = pnp_devices_info[0]['deviceInfo'][ 'onbState'] # verify if device is ready to be claimed: state = Unclaimed "and" onboard_state = Initialized if device_state == 'Unclaimed' and device_onb_state == 'Initialized': break else: pnp_unclaimed_device_count = 0 except: pass time.sleep(10) print('\nFound Unclaimed PnP devices count: ', pnp_unclaimed_device_count) pnp_device_id = pnp_devices_info[0]['id'] comment = '\nUnclaimed PnP device info:' comment += '\nPnP Device Hostname: ' + pnp_device_name comment += '\nPnP Device Id: ' + pnp_device_id print(comment) # create service now incident incident_number = service_now_apis.create_incident( 'AP PnP API Provisioning: ' + pnp_device_name, comment, SNOW_DEV, 3) print('Created new ServiceNow Incident: ', incident_number) # get the floor id to assign device to using pnp floor_id = dnac_apis.get_floor_id(site_name, 'Floor 3', dnac_token) print('Floor Id: ', floor_id) print('\nAP PnP Provisioning Started (this may take few minutes)') # start the claim process of the device to site claim_result = dnac_apis.pnp_claim_ap_site(pnp_device_id, floor_id, 'TYPICAL', dnac_token) comment = '\nClaim Result: ' + claim_result # update ServiceNow incident print(comment) service_now_apis.update_incident(incident_number, comment, SNOW_DEV) # check claim status every 5 seconds, build a progress status list, end when state == provisioned, exit status_list = [] claim_status = dnac_apis.pnp_get_device_info(pnp_device_id, dnac_token)['state'] status_list.append(claim_status) while claim_status != 'Provisioned': claim_status = dnac_apis.pnp_get_device_info(pnp_device_id, dnac_token)['state'] if claim_status not in status_list: status_list.append(claim_status) time.sleep(5) comment = '' for status in status_list: comment += '\nPnP Device State: ' + status # update service now incident print(comment) service_now_apis.update_incident(incident_number, comment, SNOW_DEV) # sync the PnP WLC, wait 60 seconds to complete dnac_apis.sync_device(PnP_WLC_NAME, dnac_token) print('\nDNA Center Device Re-sync started: ', PnP_WLC_NAME) # wait 60 seconds and check for inventory for AP info time.sleep(60) # collect AP info ap_device_id = dnac_apis.get_device_id_name(pnp_device_name, dnac_token) ap_device_info = dnac_apis.get_device_info(ap_device_id, dnac_token) ap_reachability = ap_device_info['reachabilityStatus'] ap_controller_ip = ap_device_info['associatedWlcIp'] ap_ip_address = ap_device_info['managementIpAddress'] ap_device_location = dnac_apis.get_device_location(pnp_device_name, dnac_token) ap_access_switch_info = dnac_apis.get_physical_topology( ap_ip_address, dnac_token) ap_access_switch_hostname = ap_access_switch_info[0] ap_access_switch_port = ap_access_switch_info[1] # collect WLC info wlc_info = dnac_apis.get_device_info_ip(ap_controller_ip, dnac_token) wlc_hostname = wlc_info['hostname'] comment = '\nProvisioned Access Point Info:\n - Reachability: ' + ap_reachability comment += '\n - IP Address: ' + ap_ip_address comment += '\n - Connected to: ' + ap_access_switch_hostname + ' , Interface: ' + ap_access_switch_port comment += '\n - Location: ' + ap_device_location comment += '\n - WLC Controller: ' + wlc_hostname + ' , IP Address: ' + ap_controller_ip print(comment) service_now_apis.update_incident(incident_number, comment, SNOW_DEV) print('\n\nAP PnP provisoning completed') service_now_apis.close_incident(incident_number, SNOW_DEV) print( '\nPnP provisioning completed successfully, ServiceNow incident closed' ) print('\n\nEnd of Application "dnac_pnp_ap.py" Run')
dnac_auth = HTTPBasicAuth(DNAC_USER, DNAC_PASS) while True: interface_number = int(input('Enter the interface number (range 2-5): ')) if 2 <= interface_number <= 5: disable_message = 'Interface GigabitEthernet1/0/' + str( interface_number) + ' disable request: ' disable_message += netconf_restconf.netconf_oper_admin_interface( 'GigabitEthernet1/0/' + str(interface_number), 'false', host_ip, 830, username, password) print('\n', disable_message) # wait for event to be created utils.time_sleep(30) enable_message = 'Interface GigabitEthernet1/0/' + str( interface_number) + ' enable request: ' enable_message += netconf_restconf.netconf_oper_admin_interface( 'GigabitEthernet1/0/' + str(interface_number), 'true', host_ip, 830, username, password) print('\n\n', enable_message) # start the Cisco DNA Center device re-sync dnac_token = dnac_apis.get_dnac_jwt_token(dnac_auth) sync_status = dnac_apis.sync_device(hostname, dnac_token) print('\nDevice sync started: ', sync_status) break
def main(): """ Vendor will join Spark Room with the name {ROOM_NAME} It will ask for access to an IP-enabled device - named {IPD} The code will map this IP-enabled device to the IP address {172.16.41.55} Access will be provisioned to allow connectivity from DMZ VDI to IPD """ last_person_email = '*****@*****.**' timer = 2 # save the initial stdout initial_sys = sys.stdout # the user will be asked if interested to run in demo mode or in # production (logging to files - erna_log.log, erna_err.log)) user_input = utils.get_input_timeout( 'If running in Demo Mode please enter y ', 10) if user_input != 'y': # open a log file 'erna.log' file_log = open('erna_log.log', 'w') # open an error log file 'erna_err.log' err_log = open('erna_err.log', 'w') # redirect the stdout to file_log and err_log sys.stdout = file_log sys.stderr = err_log # configure basic logging to send to stdout, level DEBUG, include timestamps logging.basicConfig( level=logging.DEBUG, stream=sys.stdout, format=('%(asctime)s - %(levelname)s - %(message)s')) # the local date and time when the code will start execution date_time = str(datetime.datetime.now().replace(microsecond=0)) print('\nThe app started running at this time ' + date_time) user_input = 'y' user_input = utils.get_input_timeout('Enter y to skip next section : ', 10) if user_input != 'y': # verify if Spark Space exists, if not create Spark Space, and add membership (optional) spark_room_id = spark_apis.get_room_id(ROOM_NAME) if spark_room_id is None: spark_room_id = spark_apis.create_room(ROOM_NAME) print('- ', ROOM_NAME, ' - Spark room created') # invite membership to the room spark_apis.add_room_membership(spark_room_id, APPROVER_EMAIL) spark_apis.post_room_message(ROOM_NAME, 'To require access enter : IPD') spark_apis.post_room_message(ROOM_NAME, 'Ready for input!') print('Instructions posted in the room') else: print('- ', ROOM_NAME, ' - Existing Spark room found') spark_apis.post_room_message(ROOM_NAME, 'To require access enter : IPD') spark_apis.post_room_message(ROOM_NAME, 'Ready for input!') print('- ', ROOM_NAME, ' - Spark room id: ', spark_room_id) # check for messages to identify the last message posted and the user's email who posted the message # check for the length of time required for access last_message = (spark_apis.last_user_message(ROOM_NAME))[0] while last_message == 'Ready for input!': time.sleep(5) last_message = (spark_apis.last_user_message(ROOM_NAME))[0] if last_message == 'IPD': last_person_email = ( spark_apis.last_user_message(ROOM_NAME))[1] spark_apis.post_room_message( ROOM_NAME, 'How long time do you need access for? (in minutes) : ') time.sleep(10) if ( spark_apis.last_user_message(ROOM_NAME) )[0] == 'How long time do you need access for? (in minutes) : ': timer = 30 * 60 else: timer = int( spark_apis.last_user_message(ROOM_NAME)[0]) * 60 elif last_message != 'Ready for input!': spark_apis.post_room_message(ROOM_NAME, 'I do not understand you') spark_apis.post_room_message(ROOM_NAME, 'To require access enter : IPD') spark_apis.post_room_message(ROOM_NAME, 'Ready for input!') last_message = 'Ready for input!' print('\nThe user with this email: ', last_person_email, ' asked access to IPD for ', (timer / 60), ' minutes') # get the WJT Auth token to access DNA dnac_token = dnac_apis.get_dnac_jwt_token(DNAC_AUTH) print('\nThe DNA Center auth token is: ', dnac_token) # IPD IP address - DNS lookup if available IPD_IP = '10.93.140.35' # locate IPD in the environment using DNA C ipd_location_info = dnac_apis.locate_client_ip(IPD_IP, dnac_token) remote_device_hostname = ipd_location_info[ 0] # the network device the IPD is connected to vlan_number = ipd_location_info[2] # the access VLAN number interface_name = ipd_location_info[ 1] # the interface number is connected to device_location = dnac_apis.get_device_location( remote_device_hostname, dnac_token) # network device location location_list_info = device_location.split('/') remote_device_location = location_list_info[-1] # select the building name print('\nThe IPD is connected to:') print('this interface:', interface_name, ', access VLAN:', vlan_number) print('on this device:', remote_device_hostname) print('located: ', remote_device_location) # request approval if user_input != 'y': spark_apis.post_room_message( ROOM_NAME, ('The user with this email ' + last_person_email + ' asked access to IPD for ' + str(timer / 60) + ' minutes')) spark_apis.post_room_message( ROOM_NAME, 'The IPD is connected to the switch ' + remote_device_hostname + ' at our location ' + remote_device_location) spark_apis.post_room_message(ROOM_NAME, 'To approve enter: Y/N') # check for messages to identify the last message posted and the user's email who posted the message. # looking for user - Director email address, and message = 'Y' last_message = (spark_apis.last_user_message(ROOM_NAME))[0] while last_message == 'To approve enter: Y/N': time.sleep(5) last_message = (spark_apis.last_user_message(ROOM_NAME))[0] approver_email = (spark_apis.last_user_message(ROOM_NAME))[1] if last_message == 'y' or 'Y': if approver_email == APPROVER_EMAIL: print('Access Approved') else: last_message = 'To approve enter: Y/N' print('\nApproval process completed') # get UCSD API key # ucsd_key = get_ucsd_api_key() # execute UCSD workflow to connect VDI to VLAN, power on VDI # execute_ucsd_workflow(ucsd_key, UCSD_CONNECT_FLOW) print('UCSD connect flow executed') # deployment of interface configuration files to the DC router dc_device_hostname = 'PDX-RO' template_project = 'ERNA' print('\nThe DC device name is: ', dc_device_hostname) dc_int_config_file = 'DC_Interface_Config.txt' dc_int_templ = dc_int_config_file.split('.')[ 0] # select the template name from the template file cli_file = open(dc_int_config_file, 'r') # open file with the template cli_config = cli_file.read() # read the file # validation of dc router cli template valid = dnac_apis.check_ipv4_duplicate(dc_int_config_file) if not valid: print('\nDC Router CLI Templates validated') dc_temp_valid = True dnac_apis.upload_template(dc_int_templ, template_project, cli_config, dnac_token) # upload the template to DNA C depl_id_dc_int = dnac_apis.deploy_template(dc_int_templ, template_project, dc_device_hostname, dnac_token) # deploy time.sleep(1) # deployment of routing configuration files to the DC router dc_rout_config_file = 'DC_Routing_Config.txt' dc_rout_templ = dc_rout_config_file.split('.')[ 0] # select the template name from the template file cli_file = open(dc_rout_config_file, 'r') # open file with the template cli_config = cli_file.read() # read the file dnac_apis.upload_template(dc_rout_templ, template_project, cli_config, dnac_token) # upload the template to DNA C depl_id_dc_routing = dnac_apis.deploy_template(dc_rout_templ, template_project, dc_device_hostname, dnac_token) print('\nDeployment of the configurations to the DC Router, ', dc_device_hostname, 'started') time.sleep(1) # deployment of interface configuration files to the Remote router remote_int_config_file = 'Remote_Interface_Config.txt' remote_int_templ = remote_int_config_file.split('.')[ 0] # select the template name from the template file cli_file = open(remote_int_config_file, 'r') # open file with the template cli_config = cli_file.read() # read the file dnac_apis.upload_template(remote_int_templ, template_project, cli_config, dnac_token) # upload the template to DNA C depl_id_remote_int = dnac_apis.deploy_template(remote_int_templ, template_project, remote_device_hostname, dnac_token) # deploy time.sleep(1) # deployment of routing configuration files to the Remote router remote_rout_config_file = 'Remote_Routing_Config.txt' remote_rout_templ = remote_rout_config_file.split('.')[ 0] # select the template name from the template file cli_file = open(remote_rout_config_file, 'r') # open file with the template cli_config = cli_file.read() # read the file # update the template with the localized info for the IPD # replace the $VlanId with the localized VLAN access # replace the $IPD with the IPD ip address cli_config = cli_config.replace('$IPD', IPD_IP) cli_config = cli_config.replace('$VlanId', vlan_number) # validation of remote router cli template valid = dnac_apis.check_ipv4_duplicate(cli_config) if not valid: print('\nRemote Device CLI Templates validated') remote_templ_valid = True dnac_apis.upload_template(remote_rout_templ, template_project, cli_config, dnac_token) # upload the template to DNA C depl_id_remote_routing = dnac_apis.deploy_template(remote_rout_templ, template_project, remote_device_hostname, dnac_token) # deploy print('\nDeployment of the configurations to the Remote device, ', remote_device_hostname, ' started') time.sleep(1) # check the deployment status after waiting for all jobs to complete - 5 seconds print('\nWait for DNA Center to complete template deployments') time.sleep(10) dc_interface_status = dnac_apis.check_template_deployment_status( depl_id_dc_int, dnac_token) dc_routing_status = dnac_apis.check_template_deployment_status( depl_id_dc_routing, dnac_token) remote_interface_status = dnac_apis.check_template_deployment_status( depl_id_remote_int, dnac_token) remote_routing_status = dnac_apis.check_template_deployment_status( depl_id_remote_routing, dnac_token) print('Templates deployment status: ', dc_interface_status, dc_routing_status, remote_interface_status, remote_routing_status) if dc_interface_status == 'SUCCESS' and dc_routing_status == 'SUCCESS' and remote_interface_status == 'SUCCESS' and remote_routing_status == 'SUCCESS': print('\nAll templates deployment have been successful\n') templ_deploy_status = True # synchronization of devices configured - DC and Remote Router dc_sync_status = dnac_apis.sync_device(dc_device_hostname, dnac_token)[0] remote_sync_status = dnac_apis.sync_device(remote_device_hostname, dnac_token)[0] if dc_sync_status == 202: print('\nDNA Center started the DC Router resync') if remote_sync_status == 202: print('\nDNA Center started the Remote Router resync') dc_router_tunnel = netconf_restconf.get_restconf_int_oper_status( 'Tunnel201') remote_router_tunnel = netconf_restconf.get_netconf_int_oper_status( 'Tunnel201') print('\nThe Tunnel 201 interfaces operational state:') print('From ', remote_device_hostname, ' using NETCONF -', dc_router_tunnel) print('From ', dc_device_hostname, ' using RESTCONF -', remote_router_tunnel) print('\nWait for DNA Center to complete the resync of the two devices') time.sleep(240) # start a path trace to check the path segmentation path_trace_id = dnac_apis.create_path_trace('172.16.202.1', IPD_IP, dnac_token) print('\nWait for Path Trace to complete') time.sleep(20) path_trace_info = dnac_apis.get_path_trace_info(path_trace_id, dnac_token) print('\nPath Trace status: ', path_trace_info[0]) print('\nPath Trace details: ', path_trace_info[1]) # create ASAv outside interface ACL to allow traffic outside_acl_id = asav_apis.get_asav_access_list(OUTSIDE_INT) asav_status = asav_apis.create_asav_access_list(outside_acl_id, OUTSIDE_INT, VDI_IP, IPD_IP) if asav_status == 201: print('ASAv access list updated to allow traffic from ', VDI_IP, ' to ', VDI_IP, ' on the interface ', OUTSIDE_INT) else: print('Error updating the ASAv access list on the interface ', OUTSIDE_INT) # Spark notification spark_apis.post_room_message( ROOM_NAME, 'Requested access to this device: IPD, located in our office ' + remote_device_location + ' by user ' + last_person_email + ' has been granted for ' + str(int(timer / 60)) + ' minutes') # Tropo notification - voice call voice_notification_result = spark_apis.tropo_notification() spark_apis.post_room_message( ROOM_NAME, 'Tropo Voice Notification: ' + voice_notification_result) # time.sleep(timer) input('\nInput any key to continue ! ') # # restore configurations to initial state # # restore DC router config dc_del_file = 'DC_Delete.txt' dc_del_templ = dc_del_file.split('.')[0] cli_file = open(dc_del_file, 'r') cli_config = cli_file.read() dnac_apis.upload_template(dc_del_templ, template_project, cli_config, dnac_token) depl_id_dc_del = dnac_apis.deploy_template(dc_del_templ, template_project, dc_device_hostname, dnac_token) print('\nDC Router restored to the baseline configuration') time.sleep(1) # restore Remote router config remote_del_file = 'Remote_Delete.txt' remote_del_templ = remote_del_file.split('.')[0] cli_file = open(remote_del_file, 'r') cli_config = cli_file.read() # update the template with the local info for the IPD # replace the $VlanId with the local VLAN access # replace the $IPD with the IPD ip address cli_config = cli_config.replace('$IPD', IPD_IP) cli_config = cli_config.replace('$VlanId', vlan_number) dnac_apis.upload_template(remote_del_templ, template_project, cli_config, dnac_token) print('\nRemote Router restored to the baseline configuration') time.sleep(1) # remove the ASAv outside interface ACLE that allowed traffic between VDI and IPD outside_acl_id = asav_apis.get_asav_access_list(OUTSIDE_INT) asav_status = asav_apis.delete_asav_access_list(outside_acl_id, OUTSIDE_INT) if asav_status == 204: print('\nASAv access list on the interface ', OUTSIDE_INT, ' restored to the baseline configuration') else: print('Error while restoring the ASAv access list on the interface ', OUTSIDE_INT) # execute UCSD workflow to discoconnect VDI to VLAN, power on VDI # execute_ucsd_workflow(ucsd_key, UCSD_DISCONNECT_FLOW) print('\nUCSD disconnect flow executed') # Spark notification spark_apis.post_room_message( ROOM_NAME, 'Access to this device: IPD has been terminated') # update the database with script execution access_log_file = open('access_logs.csv', 'a') data_to_append = [ date_time, last_person_email, IPD_IP, approver_email, dc_temp_valid, remote_templ_valid, templ_deploy_status, dc_router_tunnel, remote_router_tunnel, path_trace_info ] access_log_file.write(data_to_append) access_log_file.close() print('\nRecords database updated, file saved') # restore the stdout to initial value sys.stdout = initial_sys # the local date and time when the code will end execution date_time = str(datetime.datetime.now().replace(microsecond=0)) print('\n\nEnd of application run at this time ', date_time)
def main(): """ Vendor will join Webex Teams Room with the name {ROOM_NAME} It will ask for access to an IP-enabled device - named {IPD} The code will map this IP-enabled device to the IP address {10.93.140.35} Access will be provisioned to allow connectivity from DMZ VDI to IPD """ # save the initial stdout initial_sys = sys.stdout # the user will be asked if interested to run in demo mode or in # production (logging to files - erna_log.log, erna_err.log)) # user_input = utils.get_input_timeout('If running in Demo Mode please enter y ', 10) user_input = 'y' # remove this line if you want to run in production if user_input != 'y': # open a log file 'erna.log' file_log = open('erna_log.log', 'w') # open an error log file 'erna_err.log' err_log = open('erna_err.log', 'w') # redirect the stdout to file_log and err_log sys.stdout = file_log sys.stderr = err_log # configure basic logging to send to stdout, level DEBUG, include timestamps logging.basicConfig(level=logging.DEBUG, stream=sys.stdout, format='%(asctime)s - %(levelname)s - %(message)s') # logging, debug level, to file {erna_run.log} logging.basicConfig( filename='erna_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') # the local date and time when the code will start execution date_time = str(datetime.datetime.now().replace(microsecond=0)) print('\nThe Application "ERNA.py" started running at this time ' + date_time) user_input = utils.get_input_timeout('Enter y to skip next section : ', 10) user_input = 'y' # remove this line if you want to follow the approval process if user_input != 'y': # verify if Webex Teams Space exists, if not create Webex Teams Space, and add membership (optional) webex_teams_room_id = webex_teams_apis.get_space_id(ROOM_NAME) if webex_teams_room_id is None: webex_teams_room_id = webex_teams_apis.create_space(ROOM_NAME) print('- ', ROOM_NAME, ' - Webex Teams room created') # invite membership to the room webex_teams_apis.add_space_membership(ROOM_NAME, APPROVER_EMAIL) webex_teams_apis.post_space_message( ROOM_NAME, 'To require access enter : IPD') webex_teams_apis.post_space_message(ROOM_NAME, 'Ready for input!') print('Instructions posted in the room') else: print('- ', ROOM_NAME, ' - Existing Webex Teams room found') webex_teams_apis.post_space_message( ROOM_NAME, 'To require access enter : IPD') webex_teams_apis.post_space_message(ROOM_NAME, 'Ready for input!') print('- ', ROOM_NAME, ' - Webex Teams room id: ', webex_teams_room_id) # check for messages to identify the last message posted and the user's email who posted the message # check for the length of time required for access last_message = (webex_teams_apis.last_user_message(ROOM_NAME))[0] while last_message == 'Ready for input!': time.sleep(5) last_message = (webex_teams_apis.last_user_message(ROOM_NAME))[0] if last_message == 'IPD': last_person_email = ( webex_teams_apis.last_user_message(ROOM_NAME))[1] webex_teams_apis.post_space_message( ROOM_NAME, 'How long time do you need access for? (in minutes) : ') time.sleep(10) if ( webex_teams_apis.last_user_message(ROOM_NAME) )[0] == 'How long time do you need access for? (in minutes) : ': timer = 30 * 60 else: timer = int( webex_teams_apis.last_user_message(ROOM_NAME)[0]) * 60 elif last_message != 'Ready for input!': webex_teams_apis.post_space_message(ROOM_NAME, 'I do not understand you') webex_teams_apis.post_space_message( ROOM_NAME, 'To require access enter : IPD') webex_teams_apis.post_space_message(ROOM_NAME, 'Ready for input!') last_message = 'Ready for input!' print('\nThe user with this email: ', last_person_email, ' asked access to IPD for ', (timer / 60), ' minutes') # get the WJT Auth token to access DNA dnac_token = dnac_apis.get_dnac_jwt_token(DNAC_AUTH) print('\nThe DNA Center auth token is: ', dnac_token) # IPD IP address - DNS lookup if available IPD_IP = '10.93.140.35' last_person_email = '*****@*****.**' approver_email = '*****@*****.**' timer = 3600 # locate IPD in the environment using DNA C ipd_location_info = dnac_apis.locate_client_ip(IPD_IP, dnac_token) remote_device_hostname = ipd_location_info[ 0] # the network device the IPD is connected to vlan_number = ipd_location_info[2] # the access VLAN number interface_name = ipd_location_info[ 1] # the interface number is connected to device_location = dnac_apis.get_device_location( remote_device_hostname, dnac_token) # network device location location_list_info = device_location.split('/') remote_device_location = location_list_info[-1] # select the building name log_ipd_info = '\n\nThe IPD is connected to this device: ' + remote_device_hostname log_ipd_info += '\n\nThis interface: ' + interface_name + ', access VLAN: ' + vlan_number log_ipd_info += '\n\nLocated : ' + remote_device_location print(log_ipd_info) # request approval if user_input != 'y': webex_teams_apis.post_space_message( ROOM_NAME, ('The user with this email ' + last_person_email + ' asked access to IPD for ' + str(timer / 60) + ' minutes')) webex_teams_apis.post_space_message( ROOM_NAME, 'The IPD is connected to the switch ' + remote_device_hostname + ' at our location ' + remote_device_location) webex_teams_apis.post_space_message(ROOM_NAME, 'To approve enter: Y/N') # check for messages to identify the last message posted and the user's email who posted the message. # looking for user - Director email address, and message = 'Y' last_message = (webex_teams_apis.last_user_message(ROOM_NAME))[0] while last_message == 'To approve enter: Y/N': time.sleep(5) last_message = (webex_teams_apis.last_user_message(ROOM_NAME))[0] approver_email = (webex_teams_apis.last_user_message(ROOM_NAME))[1] if last_message == 'y' or 'Y': if approver_email == APPROVER_EMAIL: print('Access Approved') else: last_message = 'To approve enter: Y/N' print('\nApproval process completed') # get UCSD API key # ucsd_key = ucsd_apis.get_ucsd_api_key() # execute UCSD workflow to connect VDI to VLAN, power on VDI # ucsd_apis.execute_ucsd_workflow(ucsd_key, UCSD_CONNECT_FLOW) log_ucsd_info = '\n\nUCSD connect flow executed' print(log_ucsd_info) # deployment of cli configuration files to the dc router dc_device_hostname = 'PDX-RO' template_project = 'ERNA' print('\nThe DC device name is: ', dc_device_hostname) dc_config_file = 'DC_Config.txt' dc_config_templ = dc_config_file.split('.')[ 0] # select the template name from the template file cli_file = open(dc_config_file, 'r') # open file with the template cli_config = cli_file.read() # read the file # validation of dc router cli template dc_valid = dnac_apis.check_ipv4_duplicate(dc_config_file) log_dc_info = '' if dc_valid is False: print('\n\nDC Router CLI Template validated') log_dc_info = '\n\nDC Router CLI Templates validated' dnac_apis.upload_template(dc_config_templ, template_project, cli_config, dnac_token) # upload the template to DNA C depl_id_dc = dnac_apis.deploy_template(dc_config_templ, template_project, dc_device_hostname, dnac_token) # deploy dc template log_dc_info += '\n\nDeployment of the configurations to the DC router, ' + dc_device_hostname log_dc_info += ' started, deployment id: ' + depl_id_dc log_dc_config = '\nDC Router Config \n\n' + cli_config print(log_dc_info) time.sleep(1) # deployment of cli configuration files to the remote router remote_config_file = 'Remote_Config.txt' remote_config_templ = remote_config_file.split('.')[ 0] # select the template name from the template file cli_file = open(remote_config_file, 'r') # open file with the template cli_config = cli_file.read() # read the file # update the template with the localized info for the IPD # replace the $VlanId with the localized VLAN access # replace the $IPD with the IPD ip address cli_config = cli_config.replace('$IPD', IPD_IP) cli_config = cli_config.replace('$VlanId', vlan_number) remote_updated_config_file = 'Remote_Config_Updated.txt' updated_cli_file = open(remote_updated_config_file, 'w') updated_cli_file.write(cli_config) updated_cli_file.close() # validation of remote router cli template remote_valid = dnac_apis.check_ipv4_duplicate(remote_updated_config_file) log_remote_info = '' if remote_valid is False: log_remote_info = '\n\nRemote Device CLI Template validated' print(log_remote_info) dnac_apis.upload_template(remote_config_templ, template_project, cli_config, dnac_token) # upload the template to DNA C depl_id_remote = dnac_apis.deploy_template( remote_config_templ, template_project, remote_device_hostname, dnac_token) # deploy remote template time.sleep(1) log_remote_info += '\n\nDeployment of the configurations to the Remote device, ' + remote_device_hostname log_remote_info += ' started, deployment id: ' + depl_id_remote log_remote_config = '\nRemote Device Config \n\n' + cli_config print(log_remote_info) time.sleep(1) # check the deployment status after waiting for all jobs to complete - 10 seconds print('\nWait for DNA Center to complete template deployments') time.sleep(10) dc_status = dnac_apis.check_template_deployment_status( depl_id_dc, dnac_token) remote_status = dnac_apis.check_template_deployment_status( depl_id_remote, dnac_token) log_templ_depl_info = '\n\nTemplates deployment status DC: ' + dc_status + ', Remote: ' + remote_status print(log_templ_depl_info) if dc_status == 'SUCCESS' and remote_status == 'SUCCESS': print('\nAll templates deployment have been successful\n') templ_deploy_status = True # synchronization of devices configured - DC and Remote Router dc_sync_status = dnac_apis.sync_device(dc_device_hostname, dnac_token)[0] remote_sync_status = dnac_apis.sync_device(remote_device_hostname, dnac_token)[0] if dc_sync_status == 202: print('\nDNA Center started the DC Router resync') if remote_sync_status == 202: print('\nDNA Center started the Remote Router resync') dc_router_tunnel = netconf_restconf.get_restconf_int_oper_status( 'Tunnel201') remote_router_tunnel = netconf_restconf.get_netconf_int_oper_status( 'Tunnel201') log_tunnel_info = '\n\nThe Tunnel 201 interfaces operational state: ' log_tunnel_info += '\n\nFrom ' + remote_device_hostname + ' using NETCONF - ' + dc_router_tunnel log_tunnel_info += '\n\nFrom ' + dc_device_hostname + ' using RESTCONF - ' + remote_router_tunnel print(log_tunnel_info) print('\nWait for DNA Center to complete the resync of the two devices') time.sleep(180) print('\nSync completed, Path Trace started') # start a path trace to check the path segmentation path_trace_id = dnac_apis.create_path_trace('172.16.202.1', IPD_IP, dnac_token) print('\nWait for Path Trace to complete') time.sleep(30) path_trace_info = dnac_apis.get_path_trace_info(path_trace_id, dnac_token) log_path_trace = '\n\nPath Trace status: ' + path_trace_info[0] log_path_trace += '\n\nPath Trace details: ' + str(path_trace_info[1]) print(log_path_trace) # create ASAv outside interface ACL to allow traffic outside_acl_id = asav_apis.get_asav_access_list(OUTSIDE_INT) asav_status = asav_apis.create_asav_access_list(outside_acl_id, OUTSIDE_INT, VDI_IP, IPD_IP) if asav_status == 201: log_asav_info = '\n\nASAv access list updated to allow traffic from ' + VDI_IP + ' to ' + IPD_IP + ' on the interface ' + OUTSIDE_INT else: log_asav_info = '\n\nError updating the ASAv access list on the interface ' + OUTSIDE_INT print(log_asav_info) # Webex Teams notification webex_teams_apis.post_space_message( ROOM_NAME, 'Requested access to this device: IPD, located in our office: ' + remote_device_location + ' by user ' + last_person_email + ' has been granted for ' + str(int(timer / 60)) + ' minutes') log_access_info = '\n\nRequested access to this device: IPD, located in our office: ' log_access_info += remote_device_location + ' by user: '******' has been granted for ' + str( int(timer / 60)) + ' minutes' # create and update ServiceNow incident snow_user = '******' snow_description = 'ERNA Automation - Vendor Remote Access to IPD: ' + IPD_IP snow_incident = service_now_apis.create_incident(snow_description, log_ipd_info, snow_user, '2') comments = log_ucsd_info + log_dc_info + log_dc_config + log_remote_info + log_remote_config + log_templ_depl_info comments += log_tunnel_info + log_path_trace + log_asav_info + log_access_info service_now_apis.update_incident(snow_incident, comments, snow_user) date_time = str(datetime.datetime.now().replace(microsecond=0)) print('\n\nEnd of application "ERNA.py" provisioning run at this time ', date_time) # time.sleep(timer) # un-comment this line if time limit is required input('Press any key to continue de-provisioning ') # # restore configurations to initial state # # restore DC router config dc_rem_file = 'DC_Remove.txt' dc_rem_templ = dc_rem_file.split('.')[0] cli_file = open(dc_rem_file, 'r') cli_config = cli_file.read() dnac_apis.upload_template(dc_rem_templ, template_project, cli_config, dnac_token) depl_id_dc_rem = dnac_apis.deploy_template(dc_rem_templ, template_project, dc_device_hostname, dnac_token) print('\nDC Router restored to the baseline configuration') log_remove_info = '\n\nDC Router restored to the baseline configuration' time.sleep(1) # restore Remote router config remote_rem_file = 'Remote_Remove.txt' remote_rem_templ = remote_rem_file.split('.')[0] cli_file = open(remote_rem_file, 'r') cli_config = cli_file.read() # update the template with the local info for the IPD # replace the $VlanId with the local VLAN access # replace the $IPD with the IPD ip address cli_config = cli_config.replace('$IPD', IPD_IP) cli_config = cli_config.replace('$VlanId', vlan_number) remote_updated_remove_file = 'Remote_Remove_Updated.txt' updated_cli_file = open(remote_updated_remove_file, 'w') updated_cli_file.write(cli_config) updated_cli_file.close() dnac_apis.upload_template(remote_rem_templ, template_project, cli_config, dnac_token) depl_id_remote_rem = dnac_apis.deploy_template(remote_rem_templ, template_project, remote_device_hostname, dnac_token) print('\nRemote Router restored to the baseline configuration') log_remove_info += '\n\nRemote Device restored to the baseline configuration' time.sleep(1) # remove the ASAv outside interface ACLE that allowed traffic between VDI and IPD outside_acl_id = asav_apis.get_asav_access_list(OUTSIDE_INT) asav_status = asav_apis.delete_asav_access_list(outside_acl_id, OUTSIDE_INT) if asav_status == 204: log_asav_remove_info = '\n\nASAv access list on the interface ' + OUTSIDE_INT + ' restored to the baseline configuration' else: log_asav_remove_info = 'Error while restoring the ASAv access list on the interface ' + OUTSIDE_INT print(log_asav_remove_info) # execute UCSD workflow to disconnect VDI to VLAN, power on VDI # ucsd_apis.execute_ucsd_workflow(ucsd_key, UCSD_DISCONNECT_FLOW) log_ucsd_remove_info = '\n\nUCSD disconnect flow executed' print(log_ucsd_remove_info) # sync the remote and DC device dc_sync_status = dnac_apis.sync_device(dc_device_hostname, dnac_token)[0] remote_sync_status = dnac_apis.sync_device(remote_device_hostname, dnac_token)[0] log_sync_info = '' if dc_sync_status == 202: log_sync_info = '\n\nDNA Center started the DC Router resync' if remote_sync_status == 202: log_sync_info += '\n\nDNA Center started the Remote Router resync' print(log_sync_info) # Webex Teams notification webex_teams_apis.post_space_message( ROOM_NAME, 'Access to this device: IPD has been terminated') webex_teams_apis.post_space_message( ROOM_NAME, '----------------------------------------------') # update the database with script execution access_log_file = open('access_logs.csv', 'a') data_to_append = str('\n\n' + date_time) + ',' access_log_file.write(data_to_append) data_to_append = last_person_email + ',' + log_ipd_info + ',' + approver_email data_to_append += ',' + log_dc_info + ',' + log_remote_info + ',' + log_templ_depl_info + ',' data_to_append += log_path_trace + ',' + log_asav_info + ',\n' + snow_incident data_to_append_nolines = data_to_append.replace('\n\n', '\n') access_log_file.write(data_to_append_nolines) access_log_file.close() print('\nRecords database updated, file saved') comments = log_remove_info + log_asav_remove_info + log_ucsd_remove_info + log_sync_info service_now_apis.update_incident(snow_incident, comments, snow_user) # restore the stdout to initial value sys.stdout = initial_sys # the local date and time when the code will end execution date_time = str(datetime.datetime.now().replace(microsecond=0)) print('\n\nEnd of application "ERNA.py" run at this time ', date_time)
def main(): """ This application will: - clear the capwap ap config from C9800-CL - delete the AP from the PnP database - re-sync the WLC controller - delete the AP from the DNAC inventory """ # run the application on demand to reset the AP PnP demo print('\n\nApplication "dnac_pnp_ap_reset.py" started') # device info and site pnp_device_assign = { 'device_hostname': 'APB026.80DF.6E18', 'site_name': 'PDX', 'floor_name': 'Floor 3' } site_name = pnp_device_assign['site_name'] floor_name = pnp_device_assign['floor_name'] pnp_device_name = pnp_device_assign['device_hostname'] print('\nThis application will reset the DNA Center PnP AP demo') # 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') dnac_token = dnac_apis.get_dnac_jwt_token(DNAC_AUTH) # find if the AP is in provisioned state and delete from the PnP database pnp_devices_info = dnac_apis.pnp_get_device_list(dnac_token) device_state = pnp_devices_info[0]['deviceInfo']['state'] pnp_device_id = pnp_devices_info[0]['id'] pnp_device_ip = pnp_devices_info[0]['deviceInfo']['httpHeaders'][0][ 'value'] print('\nPnP device state: ' + device_state) if device_state != 'Unclaimed': # if AP is unclaimed, go through the process to delete all configs # connect to C9800-CL using ssh/netmiko net_connect = ConnectHandler(**DEVICE_INFO) command_output = net_connect.find_prompt() print('\nPrompt of the connected device: ', command_output) # send the command to clear the PnP AP capwap config command = 'clear ap config ' + pnp_device_name command_output = net_connect.send_command(command) print(command_output) # disconnect from the C9800-CL net_connect.disconnect() # check if error during CLI command and delete config manually if '% Error' in command_output: print( '\n\nClear AP Config All from C9800-CL>Configuration>Wireless>AP>Advanced' ) input('\nPress any key to continue') print('\nDemo reset started') # wait for the AP to delete the config and reboot time.sleep(30) print('\n\n\nPnP database device id: ' + pnp_device_id) print('PnP device IP Address: ', pnp_device_ip) # delete the device from the PnP database delete_result = dnac_apis.pnp_delete_provisioned_device( pnp_device_id, dnac_token) print('PnP database delete result: ', delete_result['deviceInfo']['state']) # get the Provisioned AP device id ap_device_id = dnac_apis.get_device_id_name(pnp_device_name, dnac_token) # sync the PnP WLC, wait 60 seconds to complete, delete the PnP device from the DNAC inventory dnac_apis.sync_device(PnP_WLC_NAME, dnac_token) print('\nDNA Center Device Re-sync started: ', PnP_WLC_NAME) time.sleep(60) delete_task_id = dnac_apis.delete_device(ap_device_id, dnac_token)['taskId'] print('Device deleted from DNA Center inventory started') time.sleep(30) delete_status = dnac_apis.check_task_id_status(delete_task_id, dnac_token) print('\nDelete task status: ', delete_status) print( '\nYou may start the demo again when the AP is available in the Cisco DNA Center PnP tab' ) print('\n\nEnd of Application "dnac_pnp_ap_reset.py" Run')