def commit_config(self): """ Commit candidate_config to the device. :return: None :raises: EXOSException, ValueError, NetMikoTimeoutException """ if self.candidate_config is None: msg = "Candidate config not loaded" self.log.error(msg) raise EXOSException(msg) try: # make a backup of the running_config self.get_running_config() # send candidate_config commands = list(set(self.candidate_config)) commands.append('save') for command in commands: output = self.device.send_command_timing(command) if 'Invalid input detected' in output: msg = "Error while sending the '{0}' command: \n{1}".format( command, output) self.log.error(msg) raise EXOSException(msg) self.candidate_config = None except (EXOSException, ValueError, NetMikoTimeoutException): self.log.error('error', exc_info=True) raise self.log.info("commit merge done")
def commit_config(self): """ Commit candidate_config to the device. :return: None :raises: EXOSException, ValueError, NetMikoTimeoutException """ # load file in the future # save configuration as-script backup # load script configuration candidate if self.candidate_config is None: raise EXOSException("Candidate config not loaded") try: # make a backup of the running_config self.get_running_config() # send candidate_config commands = list(set(self.candidate_config)) commands.append('save') for command in commands: output = self.device.send_command_timing(command) if 'Invalid input detected' in output: raise EXOSException( "Error while sending the '{0}' command:" "\n{1}".format(command, output)) self.candidate_config = None except (EXOSException, ValueError, NetMikoTimeoutException): raise
def load_candidate_config(self, filename=None, config=None): """ Populate candidate_config from str or file as a list of commands. :param filename: Path to the file containing the desired configuration. Default: None. :param config: String containing the desired configuration. Default: None. :return: None :raises: EXOSException """ if filename is None and config is None: msg = "at least one of the following attributes has to be \ provided: 'filename' or 'config'" self.log.error(msg) raise EXOSException(msg) self.candidate_config = '' if filename is not None: with open(filename) as file: self.candidate_config = file.read().splitlines() else: self.candidate_config = config.splitlines() self.candidate_config = [ line.strip() for line in self.candidate_config ] self.log.info("candidate_config loaded")
def rollback(self): """ Rollback the last committed configuration. :return: None :raises: EXOSException, ValueError, NetMikoTimeoutException """ if self.running_config is None: msg = "No previous running_config to roll back to present" self.log.error(msg) raise EXOSException(msg) try: # load the previous running_config to get back to the previous state self.candidate_config = self.running_config # remove all comments and empty lines self.candidate_config = [ x for x in self.candidate_config if not x.startswith('#') ] self.candidate_config = [ x for x in self.candidate_config if not x == '' ] # commit_replace the config self.commit_replace_config() except (EXOSException, ValueError, NetMikoTimeoutException): self.log.error('error', exc_info=True) raise
def compare_replace_config(self): """ Generate replace diff to be used to build delete commands :return: config diff :raises: EXOSException """ if self.candidate_config is None: msg = "Candidate config not loaded" self.log.error(msg) raise EXOSException(msg) self.log.info("comparing config for commit replace") # make sure we have the running_config self.get_running_config() replace_diff = difflib.unified_diff(self.running_config, self.candidate_config, fromfile='running_config.conf', tofile='candidate_config.conf', lineterm='') self.log.info("diff aquired") replace_diff = '\n'.join(replace_diff) return replace_diff
def compare_merge_config(self): """ Compare configuration to be merged, with the one on the device. Compare executed candidate config with the running config and return a diff, assuming the loaded config will be merged with the existing one. :return: config diff :raises: EXOSException """ if self.candidate_config is None: msg = "Candidate config not loaded" self.log.error(msg) raise EXOSException(msg) self.log.info("comparing config for commit merge") # make sure we have the running_config self.get_running_config() old_conf = list(set(self.running_config)) new_conf = self.running_config + self.candidate_config new_conf = list(set(new_conf)) diff = difflib.unified_diff(old_conf, new_conf, fromfile='running_config.conf', tofile='candidate_config.conf', n=0, lineterm='') self.log.info("diff aquired") return '\n'.join(list(diff))
def load_candidate_config(self, filename=None, config=None): """ Populate candidate_config from str or file as a list of commands. :param filename: Path to the file containing the desired configuration. Default: None. :param config: String containing the desired configuration. Default: None. :return: None :raises: EXOSException """ # scp to device in the future candidate.xsf if filename is None and config is None: raise EXOSException( "at least one of the following attributes has to be \ provided: 'filename' or 'confg'") self.candidate_config = '' if filename is not None: with open(filename) as file: self.candidate_config = file.read().splitlines() else: self.candidate_config = config.splitlines()
def test_pyexos_commit_replace_config_exception(self, mock_con): """ testing pyEXOS load_replace_candidate_config EXOSException """ with mock.patch.object(EXOS, 'commit_config') as mock_commit: mock_commit.side_effect = EXOSException('error') self.device.open() config = 'config' self.device.load_candidate_config(config=config) self.assertRaises(EXOSException, self.device.commit_replace_config)
def commit_replace_config(self): """ Commit candidate_config to the device, by replaceing the previous running configuration. :return: None :raises: EXOSException, ValueError, NetMikoTimeoutException """ if self.candidate_config is None: raise EXOSException("Candidate config not loaded") try: # fetch running_config to generate delete commands for it self.get_running_config() # generate delta commands self.candidate_config = self._generate_commands() # commit new candidate_config self.commit_config() except (EXOSException, ValueError, NetMikoTimeoutException): raise
def compare_replace_config(self): """ Generate replace diff to be used to build delete commands :return: config diff :raises: EXOSException """ if self.candidate_config is None: raise EXOSException("Candidate config not loaded") # make sure we have the running_config self.get_running_config() replace_diff = difflib.unified_diff( [x.strip() for x in self.running_config], [x.strip() for x in self.candidate_config], fromfile='running_config.conf', tofile='candidate_config.conf', lineterm='') replace_diff = '\n'.join(replace_diff) return replace_diff
def commit_replace_config(self): """ Commit candidate_config to the device, by replacing the previous running configuration. :return: None :raises: EXOSException, ValueError, NetMikoTimeoutException """ if self.candidate_config is None: msg = "Candidate config not loaded" self.log.error(msg) raise EXOSException(msg) try: # fetch running_config to generate delete commands for it self.get_running_config() # generate delta commands self.candidate_config = self._generate_commands() # commit new candidate_config self.commit_config() except (EXOSException, ValueError, NetMikoTimeoutException): self.log.error('error', exc_info=True) raise self.log.info("commit replace done")