def load_replace_candidate(self, filename=None, config=None): """ Only configuration files are supported with load_replace_candidate. It must be a full config file like /config/config.boot Due to the OS nature, we do not support a replace using a configuration string. """ if filename is not None: if os.path.exists(filename) is True: self._scp_client.scp_transfer_file(filename, self._DEST_FILENAME) self.device.send_command("cp " + self._BOOT_FILENAME + " " + self._BACKUP_FILENAME) output_loadcmd = self.device.send_config_set( ['load ' + self._DEST_FILENAME]) match_loaded = re.findall("Load complete.", output_loadcmd) match_notchanged = re.findall( "No configuration changes to commit", output_loadcmd) match_failed = re.findall( "Failed to parse specified config file", output_loadcmd) if match_failed: raise ReplaceConfigException("Failed replace config: " + output_loadcmd) if not match_loaded: if not match_notchanged: raise ReplaceConfigException( "Failed replace config: " + output_loadcmd) else: raise ReplaceConfigException("config file is not found") else: raise ReplaceConfigException("no configuration found")
def load_replace_candidate(self, filename=None, config=None): if config: raise ReplaceConfigException("This method requires a config file.") elif filename: if self.loaded is False: if self._save_backup() is False: raise ReplaceConfigException( 'Error while storing backup config') path = self._import_file(filename) if path is False: msg = "Error while trying to move the config file to the device." raise ReplaceConfigException(msg) # Let's load the config. cmd = '<load><config><from>{0}</from></config></load>'.format(path) self.device.op(cmd=cmd) if self.device.status == 'success': self.loaded = True else: raise ReplaceConfigException( 'Error while loading config from {0}').format(path) else: raise ReplaceConfigException("This method requires a config file.")
def load_replace_candidate(self, filename=None, config=None): self.replace = True self.loaded = True if not filename and not config: raise ReplaceConfigException( 'filename or config param must be provided.') if filename is None: temp_file = tempfile.NamedTemporaryFile() temp_file.write(config) temp_file.flush() cfg_filename = temp_file.name else: cfg_filename = filename self.replace_file = cfg_filename with open(self.replace_file, 'r') as f: file_content = f.read() file_content = self.fix_checkpoint_string(file_content, self.replace_file) temp_file = tempfile.NamedTemporaryFile() temp_file.write(file_content) temp_file.flush() self.replace_file = cfg_filename self._send_file(temp_file.name, cfg_filename)
def _commit_replace(self): cmd = self._bnc_cmd(self.filename_candidate, "replace", "continue-on-error") self._send_rpc(cmd) if self.error.getvalue(): self.rollback() raise ReplaceConfigException(self.error.getvalue())
def _send_file(self, filename, dest): self.fc = FileCopy(self.device, filename, dst=dest.split('/')[-1]) try: if not self.fc.remote_file_exists(): self.fc.send() elif not self.fc.file_already_exists(): self.fc.send() except NXOSFileTransferError as fte: raise ReplaceConfigException(fte.message)
def load_replace_candidate(self, filename=None, config=None): self.config_replace = True error_marker = 'Failed to parse specified config file' if config: raise NotImplementedError if not filename: raise ReplaceConfigException("filename empty") self.scp_file(source_file=filename, dest_file=self.candidate_cfg) self.device.config_mode() cmd = 'load {}'.format(self.candidate_cfg) output = self.device.send_command(cmd, expect_string='#') if error_marker in output: self.discard_config() raise ReplaceConfigException(output)
def discard_config(self): if self.loaded: discard_cmd = '<load><config><from>{0}</from></config></load>'.format(self.backup_file) self.device.op(cmd=discard_cmd) if self.device.status == 'success': self.loaded = False self.merge_config = False else: raise ReplaceConfigException("Error while loading backup config.")
def commit_config(self): try: self._execute_command_with_vdom( 'execute backup config flash commit_with_napalm') self.device.commit() self.discard_config() except FailedCommit as e: if self.config_replace: raise ReplaceConfigException(e.message) else: raise MergeConfigException(e.message)
def commit_config(self): """ Netmiko is being used to commit the configuration because it takes a better care of results compared to pan-python. """ if self.loaded: if self.ssh_connection is False: self._open_ssh() try: self.ssh_device.commit() time.sleep(3) self.loaded = False self.changed = True except: # noqa if self.merge_config: raise MergeConfigException('Error while commiting config') else: raise ReplaceConfigException('Error while commiting config') else: raise ReplaceConfigException('No config loaded.')
def load_replace_candidate(self, filename=None, config=None): self.config_replace = True if config: raise NotImplementedError if filename: self.filename = os.path.basename(filename) try: self._upload_scf(filename) except Exception as err: raise ReplaceConfigException('{}'.format(err))
def _send_file(self, filename, dest): self.fc = FileCopy(self.device, filename, dst=dest.split('/')[-1]) try: if not self.fc.remote_file_exists(): self.fc.send() elif not self.fc.file_already_exists(): commands = [ 'terminal dont-ask', 'delete {0}'.format(self.fc.dst) ] self.device.config_list(commands) self.fc.send() except NXOSFileTransferError as fte: raise ReplaceConfigException(fte.message)
def rollback(self): """Rollback configuration to filename or to self.rollback_cfg file.""" filename = None if filename is None: filename = self._BACKUP_FILENAME output_loadcmd = self.device.send_config_set(['load ' + filename]) match = re.findall("Load complete.", output_loadcmd) if not match: raise ReplaceConfigException("Failed rollback config: " + output_loadcmd) else: self.device.send_config_set(['commit', 'save'])
def commit_config(self, save=True): self.config_replace = False error_marker = 'Failed to generate committed config' output = self.device.send_command('commit', expect_string='#', delay_factor=.1) if error_marker in output: self.discard_config() raise ReplaceConfigException(output) if save: self.device.send_command('save', expect_string='#') self.device.send_command('exit', expect_string='$')
def _load_config(self): cmd = 'rollback running file {0}'.format( self.replace_file.split('/')[-1]) self._disable_confirmation() try: rollback_result = self.device.config(cmd) except ConnectionError: # requests will raise an error with verbose warning output return True except Exception: return False if 'Rollback failed.' in rollback_result['msg']: raise ReplaceConfigException(rollback_result['msg']) return True
def commit_config(self): if self.loaded: self.backup_file = 'config_' + str(datetime.now()).replace(' ', '_') install_config.save_config(self.device, self.backup_file) if self.replace: if install_config.rollback(self.device, self.fc.dst) is False: raise ReplaceConfigException else: try: self._commit_merge() except Exception as e: raise MergeConfigException(str(e)) self.changed = True self.loaded = False else: raise ReplaceConfigException('No config loaded.')
def load_replace_candidate(self, filename=None, config=None): self.replace = True self.loaded = True if filename is None: temp_file = tempfile.NamedTemporaryFile() temp_file.write(config) temp_file.flush() cfg_file_path = temp_file.name else: cfg_file_path = filename self.fc = FileCopy(self.device, cfg_file_path) if not self.fc.file_already_exists(): try: self.fc.transfer_file() except FileTransferError as fte: raise ReplaceConfigException(fte.message)
def commit_config(self): if self.loaded: self.backup_file = 'config_' + str(datetime.now()).replace( ' ', '_') self._save_config(self.backup_file) if self.replace: if self._load_config() is False: raise ReplaceConfigException else: try: self._commit_merge() self.merge_candidate = '' # clear the merge buffer except Exception as e: raise MergeConfigException(str(e)) self.changed = True self.loaded = False else: raise ReplaceConfigException('No config loaded.')
def rollback(self): """ Netmiko is being used to commit the rollback configuration because it takes a better care of results compared to pan-python. """ if self.changed: rollback_cmd = '<load><config><from>{0}</from></config></load>'.format(self.backup_file) self.device.op(cmd=rollback_cmd) time.sleep(5) if self.ssh_connection is False: self._open_ssh() try: self.ssh_device.commit() self.loaded = False self.changed = False self.merge_config = False except: # noqa ReplaceConfigException("Error while loading backup config")
def commit_config(self): """Implementation of NAPALM method commit_config.""" if self.loaded: if self.replace: try: self.device.commit_replace_config() except Exception as e: self.device.rollback() raise ReplaceConfigException(str(e)) else: try: self.device.commit_config() except Exception as e: self.device.rollback() raise MergeConfigException(str(e)) else: raise MergeConfigException('No config loaded.') self.changed = True self.loaded = False
def _get_diff(self, cp_file): """Get a diff between running config and a proposed file.""" diff = [] self._create_sot_file() diff_out = self.device.show( 'show diff rollback-patch file {0} file {1}'.format( 'sot_file', self.replace_file.split('/')[-1]), raw_text=True) try: diff_out = diff_out.split('#Generating Rollback Patch')[1].replace( 'Rollback Patch is Empty', '').strip() for line in diff_out.splitlines(): if line: if line[0].strip() != '!': diff.append(line.rstrip(' ')) except (AttributeError, KeyError): raise ReplaceConfigException( 'Could not calculate diff. It\'s possible the given file doesn\'t exist.' ) return '\n'.join(diff)
def _load_candidate(self, filename, config, overwrite): if filename is None: configuration = config else: with open(filename) as f: configuration = f.read() if not self.config_lock: # if not locked during connection time # will try to lock it if not already aquired self.lock() # and the device will be locked till first commit/rollback try: self.device.cu.load(configuration, format='text', overwrite=overwrite) except ConfigLoadError as e: if self.config_replace: raise ReplaceConfigException(e.message) else: raise MergeConfigException(e.message)
def _load_config(self, filename=None, config=None, replace=True): if self.config_session is not None: raise SessionLockedException('Session is already in use by napalm') else: self.config_session = 'napalm_{}'.format( datetime.now().microsecond) commands = list() commands.append('configure session {}'.format(self.config_session)) if replace: commands.append('rollback clean-config') if filename is not None: with open(filename, 'r') as f: lines = f.readlines() else: if isinstance(config, list): lines = config else: lines = config.splitlines() for line in lines: line = line.strip() if line == '': continue if line.startswith('!'): continue commands.append(line) try: self.device.run_commands(commands) except pyeapi.eapilib.CommandError as e: self.discard_config() if replace: raise ReplaceConfigException(e.message) else: raise MergeConfigException(e.message)