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): if not filename and not config: raise ReplaceConfigException('filename or config parameter must be provided.') if not filename: tmp_file = self._create_tmp_file(config) filename = tmp_file else: if not os.path.isfile(filename): raise ReplaceConfigException("File {} not found".format(filename)) try: transfer_result = file_transfer( self._netmiko_device, source_file=filename, dest_file=self.candidate_cfg, file_system=self._dest_file_system, direction="put", overwrite_file=True, ) if not transfer_result['file_exists']: raise ValueError() except Exception: msg = ('Could not transfer file. There was an error ' 'during transfer. Please make sure remote ' 'permissions are set.') raise ReplaceConfigException(msg) self.replace = True self.loaded = True if config and os.path.isfile(tmp_file): os.remove(tmp_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.encode()) temp_file.flush() self.replace_file = cfg_filename self._send_file(temp_file.name, cfg_filename)
def rollback(self): if self.changed: command = "rollback running-config file {}".format(self.rollback_cfg) result = self._send_command(command) if "completed" not in result.lower(): raise ReplaceConfigException(result) self._copy_run_start() self.changed = False
def load_replace_candidate(self, filename=None, config=None): """Open the candidate config and replace.""" if not filename and not config: raise ReplaceConfigException('filename or config param must be provided.') self._replace_candidate(filename, config) self.replace = True self.loaded = True
def _load_cfg_from_checkpoint(self): command = 'rollback running file {0}'.format( self.replace_file.split('/')[-1]) self._disable_confirmation() rollback_result = self.device.send_command(command) if 'Rollback failed.' in rollback_result or 'ERROR' in rollback_result: raise ReplaceConfigException(rollback_result) elif rollback_result == []: raise ReplaceConfigException
def rollback(self): if self.changed: command = 'rollback running-config file {}'.format( self.backup_file) result = self.device.send_command(command) if 'completed' not in result.lower(): raise ReplaceConfigException(result) self._copy_run_start() self.changed = False
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 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 if os.path.exists(cfg_filename) is True: self._scp_client.scp_transfer_file(cfg_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")
def _replace_candidate(self, filename, config): if not filename: filename = self._create_tmp_file(config) else: if not os.path.isfile(filename): raise ReplaceConfigException( "File {} not found".format(filename)) self.replace_file = filename if not self._enough_space(self.replace_file): msg = 'Could not transfer file. Not enough space on device.' raise ReplaceConfigException(msg) need_transfer = True if self._check_file_exists(self.replace_file): if self._check_md5(self.replace_file): need_transfer = False if need_transfer: dest = os.path.basename(self.replace_file) # full_remote_path = 'flash:/{}'.format(dest) with paramiko.SSHClient() as ssh: ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname=self.hostname, username=self.username, password=self.password, port=self.port, look_for_keys=False) try: with paramiko.SFTPClient.from_transport( ssh.get_transport()) as sftp_client: sftp_client.put(self.replace_file, dest) # with SCPClient(ssh.get_transport()) as scp_client: # scp_client.put(self.replace_file, dest) except Exception as e: msg = 'Could not transfer file. There was an error during transfer:' + str( e) raise ReplaceConfigException(msg) self.config_replace = True if config and os.path.isfile(self.replace_file): os.remove(self.replace_file)
def load_replace_candidate(self, filename=None, config=None): """ Populates the candidate configuration. You can populate it from a file or from a string. If you send both a filename and a string containing the configuration, the file takes precedence. If you use this method the existing configuration will be replaced entirely by the candidate configuration once you commit the changes. This method will not change the configuration by itself. :param filename: Path to the file containing the desired configuration. By default is None. :param config: String containing the desired configuration. :raise ReplaceConfigException: If there is an error on the configuration sent. """ file_content = "" if filename is None and config is None: # if nothing is entered returns none print("No filename or config was entered") return None if filename is not None: try: file_content = open(filename, "r") # attempts to open file temp = file_content.read() # stores file content self.config_replace = FastIronDriver.__creates_list_of_nlines( temp) self.replace_config = True # file opened successfully return except ValueError: raise ReplaceConfigException("Configuration error") if config is not None: try: self.config_replace = FastIronDriver.__creates_list_of_nlines( config) self.replace_config = True # string successfully saved return except ValueError: raise ReplaceConfigException("Configuration error") raise ReplaceConfigException("Configuration error")
def _load_cfg_from_checkpoint(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 (don't fail on this). return if 'Rollback failed.' in rollback_result[ 'msg'] or 'ERROR' in rollback_result: raise ReplaceConfigException(rollback_result['msg'])
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): """ 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 _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(py23_compat.text_type(fte))
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 _load_cfg_from_checkpoint(self): commands = [ "terminal dont-ask", "rollback running-config file {}".format(self.candidate_cfg), "no terminal dont-ask", ] try: rollback_result = self._send_command_list(commands) finally: self.changed = True msg = rollback_result if "Rollback failed." in msg: raise ReplaceConfigException(msg)
def load_replace_candidate(self, filename=None, config=None): """ file to device filesystem, defaults to candidate_config. Return None or raise exception """ self.config_replace = True return_status, msg = self._load_candidate_wrapper( source_file=filename, source_config=config, dest_file=self.candidate_cfg, ) if not return_status: raise ReplaceConfigException(msg)
def commit_config(self, message=""): if message: raise NotImplementedError('Commit message not implemented for this platform') if self.loaded: # Create checkpoint from current running-config self._save_to_checkpoint(self.rollback_cfg) if self.replace: self._load_cfg_from_checkpoint() else: self._commit_merge() self._copy_run_start() self.loaded = False else: raise ReplaceConfigException('No config loaded.')
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 commit_config(self): if self.loaded: # Create checkpoint from current running-config self.backup_file = 'config_' + str(datetime.now()).replace( ' ', '_') self._save_to_checkpoint(self.backup_file) if self.replace: # Replace operation self._load_cfg_from_checkpoint() else: # Merge operation self._commit_merge() self._copy_run_start() 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 load_replace_candidate(self, filename=None, config=None): """Replace running config with the candidate.""" """ Implentation of napalm module load_replace_candidate() ArubaOS-Switch supports payload_type options: - "RPT_PATCH_FILE" -> not implemented - "RPT_BACKUP_FILE" -> Implemented Note: the maximum content_length = 16072, "HTTP/1.1 413 Request Entity Too Large" is returned above that!!! """ url = self._api_url + 'system/config/payload' payload = {"payload_type": "RPT_BACKUP_FILE"} if filename is not None: config = self._read_candidate(filename) if config is not None: payload['config_base64_encoded'] = ArubaOSS._str_to_b64(config) load = self._apisession.post(url, json=payload) if load.status_code != 200: raise ReplaceConfigException("Load configuration failed")
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): """Get a diff between running config and a proposed file.""" diff = [] self._create_sot_file() command = ('show diff rollback-patch file {0} file {1}'.format( 'sot_file', self.replace_file.split('/')[-1])) diff_out = self.device.send_command(command) 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() != '!' and 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_cfg_from_checkpoint(self): commands = ['terminal dont-ask', 'rollback running-config file {}'.format(self.candidate_cfg), 'no terminal dont-ask'] try: rollback_result = self._send_command_list(commands) except ConnectionError: # requests will raise an error with verbose warning output (don't fail on this). return finally: self.changed = True # For nx-api a list is returned so extract the result associated with the # 'rollback' command. rollback_result = rollback_result[1] msg = rollback_result.get('msg') if rollback_result.get('msg') else rollback_result error_msg = True if rollback_result.get('error') else False if 'Rollback failed.' in msg or error_msg: raise ReplaceConfigException(msg) elif rollback_result == []: raise ReplaceConfigException
def commit_config(self, message=""): if message: raise NotImplementedError( 'Commit message not implemented for this platform') if self.loaded: # Create checkpoint from current running-config self.backup_file = 'config_' + str(datetime.now()).replace( ' ', '_') self._save_to_checkpoint(self.backup_file) if self.replace: # Replace operation self._load_cfg_from_checkpoint() else: # Merge operation self._commit_merge() self._copy_run_start() self.changed = True self.loaded = False else: raise ReplaceConfigException('No config loaded.')
def _verify_remote_file_exists(self, dst, file_system='flash:'): command = 'dir {0}/{1}'.format(file_system, dst) output = self.device.send_command(command) if 'No file found' in output: raise ReplaceConfigException('Could not transfer file.')