def _prepare_issu(self, steps, upgrade_image): """Prepare the device for ISSU: 1. Check currect image version and upgrade image version 2. Copy upgrade image to standby RP Raises: Unicon errors Exception Example: >>> _prepare_issu(steps=steps, upgrade_image='someimage') """ # Init device = self.device filetransfer = FileUtils.from_device(device) if not device.filetransfer_attributes['protocol']: raise Exception( "Unable to continue ISSU process, file transfer " "'protocol' is missing. Check the testbed yaml file and the " "provided arguments.") for disk in ['harddisk:', 'stby-harddisk:']: # Check for space on RP and SRP logger.info("Verify '{}' has enough space".format(disk)) try: self.check_disk_space(device=device, disk=disk, image=upgrade_image) except Exception as e: raise Exception( "FAIL: Device '{}' does not have enough space -" " skipping ISSU".format(disk)) # Copy ISSU upgrade image to disk logger.info("Copy ISSU upgrade image to {}".format(disk)) from_url = '{protocol}://{address}/{upgrade_image}'.format( protocol=device.filetransfer_attributes['protocol'], address=device.filetransfer_attributes['server_address'], upgrade_image=upgrade_image) filetransfer.copyfile(source=from_url, destination=disk, device=device, timeout_seconds='600') # Verify location:<filename> exists output = device.execute('dir {disk}{image}'.format( disk=disk, image=basename(upgrade_image))) if 'Error' not in output: logger.info("Copied ISSU image to '{}'".format(disk)) else: raise Exception( "Unable to copy ISSU image to '{}'".format(disk))
def save_configuration(self, device, method, abstract, default_dir): if method == 'checkpoint': # compose checkpoint name self.ckname = self.__class__.__name__ + \ time.ctime().replace(' ', '_').replace(':', '_') # Create checkpoint self.create_delete_checkpoint(device=device, name=self.ckname, action='create') # Check if checkpoint is successfully created self.check_checkpoint_status(device=device, name=self.ckname, abstract=abstract) # Return checkpoint name generated to caller return self.ckname elif method == 'local': self.run_config = device.execute('show running-config') elif method == 'config_replace': # Create unique filename self.filename = self.__class__.__name__ + \ time.ctime().replace(' ', '_').replace(':', '_') # Set from/to locations self.from_url = 'running-config' self.to_url = '{dir}{filename}'.format( filename=self.filename, dir=default_dir[device.name]) # Instantiate a filetransferutils instance for NXOS device self.filetransfer = FileUtils.from_device(device) # Execute copy running-config to location:<filename> self.filetransfer.copyconfiguration(source=self.from_url, destination=self.to_url, device=device) # Verify location:<filename> exists created = self.filetransfer.stat(target=self.to_url, device=device) if created: log.info("Successfully created '{}'".format(self.to_url)) else: raise Exception("Unable to create '{}'".format(self.to_url)) # Return filename generated to caller return self.to_url
def copy_issu_image_to_disk(device, disk, path, address, image, protocol="tftp"): """ Copy image from a server to disk Args: device ('obj'): Device object disk ('str'): Disk name address ('str'): Server address path ('str'): Path on server protocol ('str'): Transfer protocol image ('str'): Image name Raises: Exception: Failed copying ISSU image to disk Returns: None """ from_url = "{protocol}://{address}//{path}/{image}".format( protocol=protocol, address=address, path=path, image=image) filetransfer = FileUtils.from_device(device) filetransfer.copyfile(source=from_url, destination=disk, device=device, timeout_seconds="600") output = device.execute("dir {disk}{image}".format(disk=disk, image=basename(image))) if "Error" not in output: log.info("Copied ISSU image to '{disk}'".format(disk=disk)) else: raise Exception( "Unable to copy ISSU image to '{disk}'".format(disk=disk))
def upload_to_server(device, core_list, *args, **kwargs): # Init status= OK # Get info port = kwargs['port'] server = kwargs['server'] timeout = kwargs['timeout'] destination = kwargs['destination'] protocol = kwargs['protocol'] username = kwargs['username'] password = kwargs['password'] # Check values are not None for item in kwargs: if item in ['protocol', 'server', 'destination', 'username', 'password'] and \ kwargs[item] is None: meta_info = "Unable to upload core dump - parameters `{}` not provided."\ " Required parameters are: `protocol`, `server`, "\ "`destination`, `username`, `password`".format(item) return ERRORED(meta_info) # Upload each core found for core in core_list: # Sample command: # copy core://<module-number>/<process-id>[/instance-num] # tftp:[//server[:port]][/path] vrf management path = '{dest}/core_{pid}_{process}_{date}_{time}'.format( dest = destination, pid = core['pid'], process = core['process'], date = core['date'], time = time.time()) if port: server = '{server}:{port}'.format(server = server, port = port) if 'instance' in core: pid = '{pid}/{instance}'.format(pid = core['pid'], instance = core['instance']) message = "Core dump upload attempt from module {} to {} via server {}".\ format(core['module'], destination, server) # construction the module/pid for the copy process core['core'] = '{module}/{pid}'.format(module = core['module'], pid = core['pid']) try: # Check if filetransfer has been added to device before or not if not hasattr(device, 'filetransfer'): device.filetransfer = FileUtils.from_device(device) to_URL = '{protocol}://{address}/{path}'.format( protocol=protocol, address=server, path=path) from_URL = 'core://{core_path}'.format(core_path=core['core']) device.filetransfer.copyfile(device=device, source=from_URL, destination=to_URL) except Exception as e: if 'Tftp operation failed' in str(e): meta_info = "Core dump upload operation failed: {}".format( message) logger.error(meta_info) status += ERRORED(meta_info) else: # Handle exception logger.error(e) status += ERRORED("Failed: {}".format(message)) else: meta_info = "Core dump upload operation passed: {}".format(message) logger.info(meta_info) status += OK(meta_info) return status
def restore_configuration(self, device, method, abstract, iteration=10, interval=60, compare=False, compare_exclude=[]): if method == 'checkpoint': # Enable the feature dialog = Dialog([ Statement(pattern=r'\[no\]', action='sendline(y)', loop_continue=True, continue_timer=False) ]) for i in range(1, iteration): # replace config with checkpoint cfg ='load disk0:{name}\n'\ 'commit replace'.format(name=self.ckname) output = device.configure(cfg, reply=dialog) if 'fail' not in output: break elif i == iteration - 1: raise Exception('Failed to rollback config to checkpoint') else: log.info('Rollback checkpoint failed: sleeping {} seconds ' 'and retrying...'.format(interval)) time.sleep(interval) # need to delete the config file on the device dialog = Dialog([ Statement(pattern=r'\[confirm\]', action='sendline(y)', loop_continue=True, continue_timer=False) ]) device.execute('delete disk0:{name}'.format(name=self.ckname), reply=dialog) # Keeping them for later enhancement elif method == 'local': pass elif method == 'config_replace': for i in range(1, iteration): # Execute commit replace cmd = "load {}\n"\ "commit replace".format(self.to_url) output = device.configure(cmd) if 'Failed to commit' not in output: break elif i == iteration - 1: raise Exception('Unable to execute commit replace') else: log.info( 'Commit replace failed: sleeping {} seconds before' ' retrying.'.format(interval)) device.execute('show configuration failed') time.sleep(interval) # Compare restored configuration to details in file if compare: log.info( "Comparing current running-config with config-replace file" ) # Default exclude = [ 'device', 'maker', 'diff_ignore', 'callables', '(Current configuration.*)' ] if compare_exclude: if isinstance(compare_exclude, str): exclude.extend([compare_exclude]) else: exclude.extend(compare_exclude) # show run show_run_output = device.execute('show running-config') show_run_config = Config(show_run_output) show_run_config.tree() # location:<filename> contents more_file = device.execute('more {}'.format(self.to_url)) more_file_config = Config(more_file) more_file_config.tree() # Diff 'show run' and config replace file contents diff = Diff(show_run_config.config, more_file_config.config, exclude=exclude) diff.findDiff() # Check for differences if len(diff.diffs): log.error("Differences observed betweenrunning-config and " "config-replce file:'{f}' for device {d}:".\ format(f=self.to_url, d=device.name)) log.error(str(diff.diffs)) raise Exception( "Comparison between running-config and " "config-replace file '{f}' failed for device" " {d}".format(f=self.to_url, d=device.name)) else: log.info("Comparison between running-config and config-replace" "file '{f}' passed for device {d}".\ format(f=self.to_url, d=device.name)) # Delete location:<filename> self.filetransfer = FileUtils.from_device(device) self.filename = self.to_url self.filetransfer.deletefile(target=self.to_url, device=device) # Verify location:<filename> deleted dir_output = self.filetransfer.dir(target=self.to_url, device=device) for file in dir_output: if self.filename in file: break else: log.info("Successfully deleted '{}'".format(self.to_url)) return raise Exception("Unable to delete '{}'".format(self.to_url)) else: pass
def _perform_issu(self, steps, upgrade_image, timeout=300): """Perform the ISSU steps in sequence on the ASR1K device: 1. Execute 'issu loadversion' to begin ISSU process 2. Poll until standby RP reaches 'ok' state 3. Verify ISSU state is now 'loadversion' 4. Execute 'issu runversion' to initiate RP failover 5. Reconnect to the device 6. Verify ISSU state is now 'runversion' 7. Execute 'issu acceptversion' to cancel rollback timer 8. Verify ISSU state is now 'acceptversion' 9. Verify ISSU rollback timer has been cancelled 10. Poll until standby RP reaches 'ok' state 11. Save running-configuration to startup-configuration 12. Execute 'issu commitversion' to complete ISSU process 13. Reload the device and then reconnect to it 14. Verify device is now booted with ISSU upgrade image Raises: Unicon errors Exception Example: >>> _perform_issu(steps=steps, upgrade_image='someimage') """ # Init device = self.device lookup = Lookup.from_device(device) filetransfer = FileUtils.from_device(device) image_name = basename(upgrade_image) # ====================================================================== # Get standby RP # ====================================================================== with steps.start("Get standby RP information", continue_=True) as step: platform_dict = lookup.parser.show_platform.\ ShowPlatform(device=device).parse() # Standby RP rs = R([ 'slot', '(?P<val1>.*)', 'rp', '(?P<val2>.*)', 'state', 'ok, standby' ]) ret = find([platform_dict], rs, filter_=False, all_keys=True) if not ret: raise Exception( "Device '{}' does not have standby RP - cannot " "perform ISSU".format(device.name)) standby_rp = ret[0][1][1] srp = re.search('(?P<srp>(\d))', standby_rp).groupdict()['srp'] logger.info("Standby RP on '{dev}' is: '{standby_rp}'".format( dev=device.name, standby_rp=standby_rp)) # ====================================================================== # issu loadversion # ====================================================================== with steps.start("Execute 'issu loadversion' to begin ISSU process", continue_=True) as step: try: output = device.execute('issu loadversion rp {srp} file ' 'stby-harddisk:{image}'.format( srp=srp, image=image_name), timeout=600) if 'FAILED' in output: device.execute('issu abortversion', timeout=timeout) raise Exception("Unable to execute 'issu loadversion'") except Exception as e: raise Exception("Unable to execute 'issu loadversion'") # Poll until standby RP reaches 'ok' state in 'show platform' logger.info("Poll until standby RP reaches 'ok' state") platform_timeout = Timeout(max_time=1200, interval=120) while platform_timeout.iterate(): platform_dict = lookup.parser.show_platform.\ ShowPlatform(device=device).parse() # Create requirement to find standby-RP with 'ok, standby' state rs = R([ 'slot', '(?P<val1>.*)', 'rp', '(?P<val2>.*)', 'state', 'ok, standby' ]) ret = find([platform_dict], rs, filter_=False, all_keys=True) if ret: logger.info("Stanby RP '{}' is in 'ok' state".\ format(standby_rp)) break # Standby RP is not 'ok' state as yet, sleep and recheck platform_timeout.sleep() # Verify issu state logger.info("Verify ISSU state is now 'loadversion'") try: self.check_issu_state(device=device, slot=standby_rp, expected_state='loadversion') logger.info("ISSU state is 'loadversion' as exepcted") except Exception as e: raise Exception(str(e)) # ====================================================================== # issu runversion # ====================================================================== with steps.start("Execute 'issu runversion' to initiate RP failover", continue_=True) as step: try: output = device.execute('issu runversion', timeout=timeout) except SubCommandFailure: # Timeout Unicon SubCommandFailure expected # Wait a bit as the device is booting with the ISSU upgrade image time.sleep(timeout) pass # Reconnect to device logger.info("Reconnect to the device after runversion") reconnect_timeout = Timeout(max_time=1200, interval=120) self._reconnect(steps=steps, timeout=reconnect_timeout) # Verify issu state logger.info("Verify ISSU state is now 'runversion'") try: self.check_issu_state(device=device, slot=standby_rp, expected_state='runversion') logger.info("ISSU state is 'runversion' as exepcted") except Exception as e: raise Exception(str(e)) # ====================================================================== # issu acceptversion # ====================================================================== with steps.start( "Execute 'issu acceptversion' to cancel rollback timer", continue_=True) as step: try: output = device.execute('issu acceptversion', timeout=timeout) if 'FAILED' in output: raise Exception("Unable to execute 'issu acceptversion'") except Exception as e: raise Exception("Unable to execute 'issu acceptversion'", from_exception=e) # Verify issu state logger.info("Verify ISSU state is now 'acceptversion'") try: self.check_issu_state(device=device, slot=standby_rp, expected_state='acceptversion') logger.info("ISSU state is 'acceptversion' as exepcted") except Exception as e: raise Exception(str(e)) # Verify rollback timer logger.info("Verify ISSU rollback timer is now 'inactive'") try: self.check_issu_rollback_timer(device=device, slot=standby_rp, expected_state='inactive') logger.info("ISSU rollback timer is 'inactive' as exepcted") except Exception as e: raise Exception(str(e)) # Poll until standby RP reaches 'ok' state in 'show platform' logger.info("Poll until standby RP reaches 'ok' state") platform_timeout = Timeout(max_time=1200, interval=120) while platform_timeout.iterate(): platform_dict = lookup.parser.show_platform.\ ShowPlatform(device=device).parse() # Create requirement to find standby-RP with 'ok, standby' state rs = R([ 'slot', '(?P<val1>.*)', 'rp', '(?P<val2>.*)', 'state', 'ok, standby' ]) ret = find([platform_dict], rs, filter_=False, all_keys=True) if ret: logger.info("Stanby RP '{}' is in 'ok' state".\ format(standby_rp)) break # Standby RP is not 'ok' state as yet, sleep and recheck platform_timeout.sleep() # Save running-configuration to startup-configuration logger.info("Save running-configuration to startup-configuration") filetransfer.copyconfiguration(source='running-config', destination='startup-config', device=device) # ====================================================================== # issu commitversion # ====================================================================== with steps.start("Execute 'issu commitversion'", continue_=True) as step: try: output = device.execute('issu commitversion', timeout=timeout) if 'FAILED' in output: raise Exception("Unable to execute 'issu commitversion'") except Exception as e: raise Exception("Unable to execute 'issu commitversion'", from_exception=e) # ====================================================================== # reload device # ====================================================================== try: reload_timeout = Timeout(max_time=1200, interval=120) self.reload(steps=steps, timeout=reload_timeout) except Exception as e: raise Exception("Unable to reload the device after ISSU completed", from_exception=e) # ====================================================================== # verify image version # ====================================================================== with steps.start( "Verify device is loaded with upgraded image after ISSU", continue_=True) as step: try: output = device.execute('show version | i image') if image_name in output: logger.info("ISSU upgrade image is successfully loaded on " "the device '{}'".format(device.name)) except Exception as e: raise Exception("Unable to execute 'show version'", from_exception=e)
def perform_issu(device, image, disk, steps=Steps()): """ Execute ISSU on device Args: device ('obj'): Device object image ('str'): Image name on disk disk ('str'): Disk where is located image Raise: None Returns: None """ with steps.start("Command 'issu loadversion'") as step: slot_number = get_platform_standby_rp(device=device) if not slot_number: raise ValueError("Could not retrieve standby rp slot number") # Load version standby_slot = "R{}".format(slot_number) try: issu_loadversion(device=device, standby_slot=slot_number, disk=disk, image=image) except Exception: step.failed("Unable to execute 'issu loadversion'") with steps.start("Command 'issu runversion'") as step: if not is_platform_slot_in_state( device=device, slot=standby_slot, state="ok, standby"): step.failed("Slot {slot} is not in 'ok, standby' state".format( slot=standby_slot)) if not is_issu_terminal_state_reached_on_slot(device=device, slot=standby_slot): step.failed("Slot {slot} has not reached terminal state".format( slot=standby_slot)) # Run version try: issu_runversion(device=device) except (Exception, ConnectionError) as e: step.failed(e) with steps.start("Command 'issu acceptversion'") as step: in_state = is_issu_in_state(device=device, slot=standby_slot, expected_state="runversion") if not in_state: step.failed("Issu is not in state 'runversion'") # Accept version try: issu_acceptversion(device=device) except Exception as e: step.failed(e) with steps.start( "Save running-configuration to startup-configuration") as step: filetransfer = FileUtils.from_device(device) filetransfer.copyconfiguration( source="running-config", destination="startup-config", device=device, ) with steps.start("Command 'issu commitversion'") as step: in_state = is_issu_in_state(device=device, slot=standby_slot, expected_state="acceptversion") if not in_state: step.failed("Issu is not in state 'acceptversion'") in_state = is_issu_rollback_timer_in_state(device=device, slot=standby_slot, expected_state="inactive") if not in_state: step.failed("Issu rollback timer is not 'inactive'") # Commit version try: issu_commitversion(device=device) except Exception as e: step.failed(e) with steps.start("Reload standby slot") as step: slot_number = get_platform_standby_rp(device=device) if not slot_number: raise ValueError("Could not retrieve standby rp slot number") standby_slot = "R{}".format(slot_number) try: reload_issu_slot(device=device, slot=standby_slot) except Exception as e: step.failed(e)
def restore_configuration(self, device, method, abstract, iteration=10, interval=60, compare=False, compare_exclude=[]): if method == 'checkpoint': # Enable the feature for i in range(1, iteration): try: self.rollback_checkpoint(device=device, name=self.ckname) break except Exception as e: if i == iteration - 1: raise Exception('Unable to rollback config') else: log.error(e) log.info('Rollback configuration failed: sleeping {} ' 'seconds and retrying...'.format(interval)) time.sleep(interval) # Delete the checkpoint self.create_delete_checkpoint(device=device, name=self.ckname, action='delete') # Check if checkpoint is successfully deleted self.check_checkpoint_status(device=device, name=self.ckname, expect='delete', abstract=abstract) elif method == 'local': # reover the deivce with whole running-config device.configure(self.run_config) elif method == 'config_replace': for i in range(1, iteration): # configure replace location:<filename> output = device.execute('configure replace {}'.\ format(self.to_url)) if 'Configure replace completed successfully' in output: break elif i == iteration - 1: raise Exception('Unable to execute config replace') else: log.info( 'Config replace failed: sleeping {} seconds before' ' retrying.'.format(interval)) # Execute 'show config-replace log exec' output = device.execute('show config-replace log exec') time.sleep(interval) # Execute 'show config-replace log exec' output = device.execute('show config-replace log exec') # Check if reload is required after executing 'configure replace' if 'before switch reload' in output: raise GenieConfigReplaceWarning('Warning: reload needed after ' 'configure replace') # Compare restored configuration to details in file if compare: log.info( "Comparing current running-config with config-replace file" ) # Default exclude = [ 'device', 'maker', 'diff_ignore', 'callables', '(Current configuration.*)' ] if compare_exclude: if isinstance(compare_exclude, str): exclude.extend([compare_exclude]) else: exclude.extend(compare_exclude) # show run show_run_output = device.execute('show running-config') show_run_config = Config(show_run_output) show_run_config.tree() # location:<filename> contents more_file = device.execute('show file {}'.format(self.to_url)) more_file_config = Config(more_file) more_file_config.tree() # Diff 'show run' and config replace file contents diff = Diff(show_run_config.config, more_file_config.config, exclude=exclude) diff.findDiff() # Check for differences if len(diff.diffs): log.error("Differences observed betweenrunning-config and " "config-replce file:'{f}' for device {d}:".\ format(f=self.to_url, d=device.name)) log.error(str(diff.diffs)) raise Exception( "Comparison between running-config and " "config-replace file '{f}' failed for device" " {d}".format(f=self.to_url, d=device.name)) else: log.info("Comparison between running-config and config-replace" "file '{f}' passed for device {d}".\ format(f=self.to_url, d=device.name)) # Delete location:<filename> self.filetransfer = FileUtils.from_device(device) self.filename = self.to_url self.filetransfer.deletefile(target=self.to_url, device=device) # Verify location:<filename> deleted dir_output = self.filetransfer.dir(target=self.to_url, device=device) for file in dir_output: if self.filename in file: break else: log.info("Successfully deleted '{}'".format(self.to_url)) return raise Exception("Unable to delete '{}'".format(self.to_url)) else: # modify the device via callable function # using Conf object self.modify_func(device=device, conf=self.conf, values_dict=self.conf_argument, recover=True, **self.specific_args)
def upload_to_server(device, core_list, crashreport_list, **kwargs): # Init status = OK # Get info port = kwargs['port'] server = kwargs['server'] timeout = kwargs['timeout'] destination = kwargs['destination'] protocol = kwargs['protocol'] username = kwargs['username'] password = kwargs['password'] # Check values are not None for item in kwargs: if item in ['protocol', 'server', 'destination', 'username', 'password'] and \ kwargs[item] is None: meta_info = "Unable to upload core dump - parameters `{}` not provided."\ " Required parameters are: `protocol`, `server`, "\ "`destination`, `username`, `password`".format(item) return ERRORED(meta_info) # preparing the full list to iterate over full_list = core_list + crashreport_list if port: server = '{server}:{port}'.format(server=server, port=port) # Upload each core/crashinfo report found for item in full_list: if 'crashinfo' in item['core']: file_type = 'Crashreport' else: file_type = 'Core' message = "{} upload attempt from {} to {} via server {}".format( file_type, item['location'], destination, server) try: # Check if filetransfer has been added to device before or not if not hasattr(device, 'filetransfer'): device.filetransfer = FileUtils.from_device(device) to_URL = '{protocol}://{address}/{path}'.format(protocol=protocol, address=server, path=destination) from_URL = '{location}//{core_path}'.format( location=item['location'], core_path=item['core']) device.filetransfer.copyfile(device=device, source=from_URL, destination=to_URL) except Exception as e: if 'Tftp operation failed' in e: meta_info = "{} upload operation failed: {}".format( file_type, message) logger.error(meta_info) status += ERRORED(meta_info) else: # Handle exception logger.warning(e) status += ERRORED("Failed: {}".format(message)) meta_info = "{} upload operation passed: {}".format(file_type, message) logger.info(meta_info) status += OK(meta_info) return status
from ats.topology import loader from ats import topology from ats.utils.fileutils import FileUtils # Transferring a single file to or from a remote server tb = loader.load("testbed.yaml") # Instanciate a filetransferutils instance for the device corresponding # to the device specific OS this_device = FileUtils.from_device(tb.devices['my_device']) # copy from remote to local machine this_device.copyfile(source='scp://remote_server:/tmp/demo.txt', destination='/Users/vkozin/Downloads/', timeout_seconds=15) # copy from local to remote machine this_device.copyfile(source='/Users/vkozin/Downloads/Task_1.docx', destination='scp://remote_server:/tmp/', timeout_seconds=15) # loading testbed immediately tb = topology.loader.load(''' devices: remote_device: os: 'linux' tacacs: username: vkozin passwords: linux: '159753852'
def restore_configuration(self, device, method, abstract, iteration=10, interval=60, compare=False, compare_exclude=[]): if method == 'checkpoint': # Enable the feature for i in range(1,iteration): try: out = self.rollback_checkpoint(device=device, name=self.ckname) except Exception as e: raise Exception('Unable to rollback config') if out and 'Rollback Done' in out: break else: log.info('Rollback configuration failed: sleeping {} ' 'seconds and retrying...'.format(interval)) time.sleep(interval) else: raise Exception('Unable to rollback config') # Delete the checkpoint self.create_delete_checkpoint(device=device, name=self.ckname, abstract=abstract, action='delete') # Check if checkpoint is successfully deleted self.check_checkpoint_status(device=device, name=self.ckname, expect='delete', abstract=abstract) elif method == 'local': # reover the deivce with whole running-config device.configure(self.run_config) elif method == 'config_replace': # delete the archive file dialog = Dialog([ Statement(pattern=r'This will apply all necessary.*', action='sendline(Y)', loop_continue=True, continue_timer=False), Statement(pattern=r'less than running config.*', action='sendline(Y)', loop_continue=True, continue_timer=False), ]) for i in range(1,iteration): # configure replace location:<filename> out = device.execute('configure replace {}'.\ format(self.to_url), reply=dialog, error_pattern=[]) if out and 'Rollback Done' in out: break else: log.info('Config replace failed: sleeping {} seconds before' ' retrying.'.format(interval)) time.sleep(interval) else: raise Exception('Unable to execute config replace') # Compare restored configuration to details in file if compare: log.info("Comparing current running-config with config-replace file") # Default exclude = ['device', 'maker', 'diff_ignore', 'callables', '(Current configuration.*)', '(.*Building configuration.*)', '(.*Load for.*)', '(.*Time source.*)'] if compare_exclude: if isinstance(compare_exclude, str): exclude.extend([compare_exclude]) else: exclude.extend(compare_exclude) # show run show_run_output = device.execute('show running-config') show_run_config = Config(show_run_output) show_run_config.tree() # location:<filename> contents more_file = device.execute('more {}'.format(self.to_url)) more_file_config = Config(more_file) more_file_config.tree() # Diff 'show run' and config replace file contents diff = Diff(show_run_config.config, more_file_config.config, exclude=exclude) diff.findDiff() # Check for differences if len(diff.diffs): log.error("Differences observed betweenrunning-config and " "config-replce file:'{f}' for device {d}:".\ format(f=self.to_url, d=device.name)) log.error(str(diff.diffs)) raise Exception("Comparison between running-config and " "config-replace file '{f}' failed for device" " {d}".format(f=self.to_url, d=device.name)) else: log.info("Comparison between running-config and config-replace" "file '{f}' passed for device {d}".\ format(f=self.to_url, d=device.name)) # Delete location:<filename> self.filetransfer = FileUtils.from_device(device) self.filename = self.to_url self.filetransfer.deletefile(target=self.to_url, device=device) # Verify location:<filename> deleted dir_output = self.filetransfer.dir(target=self.to_url,device=device) for file in dir_output: if self.filename in file: break else: log.info("Successfully deleted '{}'".format(self.to_url)) return raise Exception("Unable to delete '{}'".format(self.to_url)) else: # modify the device via callable function # using Conf object self.modify_func(device=device, conf=self.conf, values_dict=self.conf_argument, recover=True, **self.specific_args)